This commit is contained in:
Phil Race 2018-09-27 10:49:10 -07:00
commit b18f1d282e
196 changed files with 5277 additions and 5587 deletions

View File

@ -513,3 +513,4 @@ ef57958c7c511162da8d9a75f0b977f0f7ac464e jdk-12+7
8f594f75e0547d4ca16649cb3501659e3155e81b jdk-12+10
f0f5d23449d31f1b3580c8a73313918cafeaefd7 jdk-12+11
15094d12a632f452a2064318a4e416d0c7a9ce0c jdk-12+12
511a9946f83e3e3c7b9dbe1840367063fb39b4e1 jdk-12+13

View File

@ -531,8 +531,8 @@ define SetupRunJtregTestBody
$1_JTREG_BASIC_OPTIONS += $$(addprefix -exclude:, $$($1_JTREG_PROBLEM_LIST))
endif
ifneq ($$(JIB_JAR), )
$1_JTREG_BASIC_OPTIONS += -cpa:$$(JIB_JAR)
ifneq ($$(JIB_HOME), )
$1_JTREG_BASIC_OPTIONS += -e:JIB_HOME=$$(JIB_HOME)
endif
$1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_GRAAL_DIR=${TEST_IMAGE_DIR}/hotspot/jtreg/graal

View File

@ -723,7 +723,7 @@ SETFILE:=@SETFILE@
XATTR:=@XATTR@
JT_HOME:=@JT_HOME@
JTREGEXE:=@JTREGEXE@
JIB_JAR:=@JIB_JAR@
JIB_HOME:=@JIB_HOME@
XCODEBUILD=@XCODEBUILD@
DTRACE := @DTRACE@
FIXPATH:=@FIXPATH@

View File

@ -1144,5 +1144,5 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JIB],
fi
fi
AC_SUBST(JIB_JAR)
AC_SUBST(JIB_HOME)
])

View File

@ -840,7 +840,7 @@ var getJibProfilesDependencies = function (input, common) {
linux_x64: "gcc7.3.0-OEL6.4+1.0",
macosx_x64: "Xcode9.4-MacOSX10.13+1.0",
solaris_x64: "SS12u4-Solaris11u1+1.0",
solaris_sparcv9: "SS12u4-Solaris11u1+1.1",
solaris_sparcv9: "SS12u6-Solaris11u3+1.0",
windows_x64: "VS2017-15.5.5+1.0",
linux_aarch64: (input.profile != null && input.profile.indexOf("arm64") >= 0
? "gcc-linaro-aarch64-linux-gnu-4.8-2013.11_linux+1.0"
@ -961,9 +961,9 @@ var getJibProfilesDependencies = function (input, common) {
ext: "zip",
classifier: "distribution",
revision: "3.0-SNAPSHOT",
environment_name: "JIB_JAR",
environment_name: "JIB_HOME",
environment_value: input.get("jib", "install_path")
+ "/jib-3.0-SNAPSHOT-distribution/lib/jib-3.0-SNAPSHOT.jar"
+ "/jib-3.0-SNAPSHOT-distribution"
},
ant: {

View File

@ -34,18 +34,19 @@
# install in a separate temporary image.
#
# The Solaris Studio installation must contain at least these packages:
# developer/developerstudio-126/backend 12.6-1.0.0.0 i--
# developer/developerstudio-126/c++ 12.6-1.0.0.0 i--
# developer/developerstudio-126/cc 12.6-1.0.0.0 i--
# developer/developerstudio-126/dbx (solarisstudio) 12.6-1.0.0.0 i--
# developer/developerstudio-126/library/c++-libs 12.6-1.0.0.0 i--
# developer/developerstudio-126/library/math-libs 12.6-1.0.0.0 i--
# developer/developerstudio-126/library/c-libs 12.6-1.0.0.0 i--
# developer/developerstudio-126/library/studio-gccrt 12.6-1.0.0.0 i--
# developer/developerstudio-126/studio-common 12.6-1.0.0.0 i--
# developer/developerstudio-126/studio-ja 12.6-1.0.0.0 i--
# developer/developerstudio-126/studio-legal 12.6-1.0.0.0 i--
# developer/developerstudio-126/studio-zhCN 12.6-1.0.0.0 i--
#developer/developerstudio-126/backend 12.6-1.0.0.1
#developer/developerstudio-126/c++ 12.6-1.0.2.0
#developer/developerstudio-126/cc 12.6-1.0.1.0
#developer/developerstudio-126/dbx 12.6-1.0.0.1
#developer/developerstudio-126/library/c++-libs 12.6-1.0.2.0
#developer/developerstudio-126/library/c-libs 12.6-1.0.0.1
#developer/developerstudio-126/library/f90-libs 12.6-1.0.0.1
#developer/developerstudio-126/library/math-libs 12.6-1.0.0.1
#developer/developerstudio-126/library/studio-gccrt 12.6-1.0.0.1
#developer/developerstudio-126/studio-common 12.6-1.0.0.1
#developer/developerstudio-126/studio-ja 12.6-1.0.0.1
#developer/developerstudio-126/studio-legal 12.6-1.0.0.1
#developer/developerstudio-126/studio-zhCN 12.6-1.0.0.1
#
# erik.joelsson@oracle.com
@ -93,7 +94,7 @@ if [ ! -d $INSTALL_ROOT ]; then
pkg -R $INSTALL_ROOT set-publisher -P -g ${PUBLISHER_URI} solaris
sudo pkg -R $INSTALL_ROOT install --accept entire@$SOLARIS_ENTIRE_VERSION \
system/install developer/gnu-binutils system/library/mmheap system/picl \
developer/assembler
developer/assembler system/library/freetype-2
else
echo "Skipping installing packages"
fi

View File

@ -36,9 +36,7 @@ ifeq ($(TOOLCHAIN_TYPE), gcc)
LAUNCHER_CFLAGS += -fvisibility=hidden
LDFLAGS_JDKEXE += -Wl,--exclude-libs,ALL
else ifeq ($(TOOLCHAIN_TYPE), clang)
ifneq ($(OPENJDK_TARGET_OS), macosx)
LAUNCHER_CFLAGS += -fvisibility=hidden
endif
LAUNCHER_CFLAGS += -fvisibility=hidden
else ifeq ($(TOOLCHAIN_TYPE), solstudio)
LAUNCHER_CFLAGS += -xldscope=hidden
else ifeq ($(TOOLCHAIN_TYPE), xlc)

View File

@ -244,7 +244,7 @@ ifeq ($(OPENJDK_TARGET_OS), aix)
EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \
EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \
OPTIMIZATION := HIGH, \
CFLAGS := $(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS_JDKLIB) $(LIBJLI_CFLAGS) \
CFLAGS := $(STATIC_LIBRARY_FLAGS) $(CFLAGS_JDKLIB) $(LIBJLI_CFLAGS) \
$(addprefix -I, $(LIBJLI_SRC_DIRS)), \
ARFLAGS := $(ARFLAGS), \
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static))

View File

@ -46,11 +46,9 @@ ifeq ($(TOOLCHAIN_TYPE), gcc)
LDFLAGS_JDKLIB += -Wl,--exclude-libs,ALL
EXPORT_ALL_SYMBOLS := -fvisibility=default
else ifeq ($(TOOLCHAIN_TYPE), clang)
ifneq ($(OPENJDK_TARGET_OS), macosx)
CFLAGS_JDKLIB += -fvisibility=hidden
CXXFLAGS_JDKLIB += -fvisibility=hidden
EXPORT_ALL_SYMBOLS := -fvisibility=default
endif
CFLAGS_JDKLIB += -fvisibility=hidden
CXXFLAGS_JDKLIB += -fvisibility=hidden
EXPORT_ALL_SYMBOLS := -fvisibility=default
else ifeq ($(TOOLCHAIN_TYPE), solstudio)
CFLAGS_JDKLIB += -xldscope=hidden
CXXFLAGS_JDKLIB += -xldscope=hidden

View File

@ -1025,37 +1025,17 @@ int LIR_Assembler::array_element_size(BasicType type) const {
return exact_log2(elem_size);
}
void LIR_Assembler::arithmetic_idiv(LIR_Op3* op, bool is_irem) {
Register Rdividend = op->in_opr1()->as_register();
Register Rdivisor = op->in_opr2()->as_register();
Register Rscratch = op->in_opr3()->as_register();
Register Rresult = op->result_opr()->as_register();
int divisor = -1;
/*
TODO: For some reason, using the Rscratch that gets passed in is
not possible because the register allocator does not see the tmp reg
as used, and assignes it the same register as Rdividend. We use rscratch1
instead.
assert(Rdividend != Rscratch, "");
assert(Rdivisor != Rscratch, "");
*/
if (Rdivisor == noreg && is_power_of_2(divisor)) {
// convert division by a power of two into some shifts and logical operations
}
__ corrected_idivl(Rresult, Rdividend, Rdivisor, is_irem, rscratch1);
}
void LIR_Assembler::emit_op3(LIR_Op3* op) {
switch (op->code()) {
case lir_idiv:
arithmetic_idiv(op, false);
break;
case lir_irem:
arithmetic_idiv(op, true);
arithmetic_idiv(op->code(),
op->in_opr1(),
op->in_opr2(),
op->in_opr3(),
op->result_opr(),
op->info());
break;
case lir_fmad:
__ fmaddd(op->result_opr()->as_double_reg(),
@ -1752,16 +1732,43 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr
}
} else if (right->is_constant()) {
jlong c = right->as_constant_ptr()->as_jlong_bits();
jlong c = right->as_constant_ptr()->as_jlong();
Register dreg = as_reg(dest);
assert(code == lir_add || code == lir_sub, "mismatched arithmetic op");
if (c == 0 && dreg == lreg_lo) {
COMMENT("effective nop elided");
return;
}
switch (code) {
case lir_add: __ add(dreg, lreg_lo, c); break;
case lir_sub: __ sub(dreg, lreg_lo, c); break;
case lir_add:
case lir_sub:
if (c == 0 && dreg == lreg_lo) {
COMMENT("effective nop elided");
return;
}
code == lir_add ? __ add(dreg, lreg_lo, c) : __ sub(dreg, lreg_lo, c);
break;
case lir_div:
assert(c > 0 && is_power_of_2_long(c), "divisor must be power-of-2 constant");
if (c == 1) {
// move lreg_lo to dreg if divisor is 1
__ mov(dreg, lreg_lo);
} else {
unsigned int shift = exact_log2_long(c);
// use rscratch1 as intermediate result register
__ asr(rscratch1, lreg_lo, 63);
__ add(rscratch1, lreg_lo, rscratch1, Assembler::LSR, 64 - shift);
__ asr(dreg, rscratch1, shift);
}
break;
case lir_rem:
assert(c > 0 && is_power_of_2_long(c), "divisor must be power-of-2 constant");
if (c == 1) {
// move 0 to dreg if divisor is 1
__ mov(dreg, zr);
} else {
// use rscratch1 as intermediate result register
__ negs(rscratch1, lreg_lo);
__ andr(dreg, lreg_lo, c - 1);
__ andr(rscratch1, rscratch1, c - 1);
__ csneg(dreg, dreg, rscratch1, Assembler::MI);
}
break;
default:
ShouldNotReachHere();
}
@ -1862,7 +1869,51 @@ void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr
void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr temp, LIR_Opr result, CodeEmitInfo* info) { Unimplemented(); }
void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr illegal, LIR_Opr result, CodeEmitInfo* info) {
// opcode check
assert((code == lir_idiv) || (code == lir_irem), "opcode must be idiv or irem");
bool is_irem = (code == lir_irem);
// operand check
assert(left->is_single_cpu(), "left must be register");
assert(right->is_single_cpu() || right->is_constant(), "right must be register or constant");
assert(result->is_single_cpu(), "result must be register");
Register lreg = left->as_register();
Register dreg = result->as_register();
// power-of-2 constant check and codegen
if (right->is_constant()) {
int c = right->as_constant_ptr()->as_jint();
assert(c > 0 && is_power_of_2(c), "divisor must be power-of-2 constant");
if (is_irem) {
if (c == 1) {
// move 0 to dreg if divisor is 1
__ movw(dreg, zr);
} else {
// use rscratch1 as intermediate result register
__ negsw(rscratch1, lreg);
__ andw(dreg, lreg, c - 1);
__ andw(rscratch1, rscratch1, c - 1);
__ csnegw(dreg, dreg, rscratch1, Assembler::MI);
}
} else {
if (c == 1) {
// move lreg to dreg if divisor is 1
__ movw(dreg, lreg);
} else {
unsigned int shift = exact_log2(c);
// use rscratch1 as intermediate result register
__ asrw(rscratch1, lreg, 31);
__ addw(rscratch1, lreg, rscratch1, Assembler::LSR, 32 - shift);
__ asrw(dreg, rscratch1, shift);
}
}
} else {
Register rreg = right->as_register();
__ corrected_idivl(dreg, lreg, rreg, is_irem, rscratch1);
}
}
void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) {
@ -2792,7 +2843,10 @@ void LIR_Assembler::align_backward_branch_target() {
}
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
// tmp must be unused
assert(tmp->is_illegal(), "wasting a register if tmp is allocated");
if (left->is_single_cpu()) {
assert(dest->is_single_cpu(), "expect single result reg");
__ negw(dest->as_register(), left->as_register());

View File

@ -75,8 +75,6 @@ friend class ArrayCopyStub;
_deopt_handler_size = 7 * NativeInstruction::instruction_size
};
void arithmetic_idiv(LIR_Op3* op, bool is_irem);
public:
void store_parameter(Register r, int offset_from_esp_in_words);

View File

@ -440,17 +440,26 @@ void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
if (x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem) {
// the check for division by zero destroys the right operand
right.set_destroys_register();
// check for division by zero (destroys registers of right operand!)
CodeEmitInfo* info = state_for(x);
left.load_item();
right.load_item();
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0));
__ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info));
bool need_zero_check = true;
if (right.is_constant()) {
jlong c = right.get_jlong_constant();
// no need to do div-by-zero check if the divisor is a non-zero constant
if (c != 0) need_zero_check = false;
// do not load right if the divisor is a power-of-2 constant
if (c > 0 && is_power_of_2_long(c)) {
right.dont_load_item();
} else {
right.load_item();
}
} else {
right.load_item();
}
if (need_zero_check) {
CodeEmitInfo* info = state_for(x);
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0));
__ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info));
}
rlock_result(x);
switch (x->op()) {
@ -506,19 +515,32 @@ void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) {
// do not need to load right, as we can handle stack and constants
if (x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem) {
right_arg->load_item();
rlock_result(x);
bool need_zero_check = true;
if (right.is_constant()) {
jint c = right.get_jint_constant();
// no need to do div-by-zero check if the divisor is a non-zero constant
if (c != 0) need_zero_check = false;
// do not load right if the divisor is a power-of-2 constant
if (c > 0 && is_power_of_2(c)) {
right_arg->dont_load_item();
} else {
right_arg->load_item();
}
} else {
right_arg->load_item();
}
if (need_zero_check) {
CodeEmitInfo* info = state_for(x);
__ cmp(lir_cond_equal, right_arg->result(), LIR_OprFact::longConst(0));
__ branch(lir_cond_equal, T_INT, new DivByZeroStub(info));
}
CodeEmitInfo* info = state_for(x);
LIR_Opr tmp = new_register(T_INT);
__ cmp(lir_cond_equal, right_arg->result(), LIR_OprFact::longConst(0));
__ branch(lir_cond_equal, T_INT, new DivByZeroStub(info));
info = state_for(x);
LIR_Opr ill = LIR_OprFact::illegalOpr;
if (x->op() == Bytecodes::_irem) {
__ irem(left_arg->result(), right_arg->result(), x->operand(), tmp, NULL);
__ irem(left_arg->result(), right_arg->result(), x->operand(), ill, NULL);
} else if (x->op() == Bytecodes::_idiv) {
__ idiv(left_arg->result(), right_arg->result(), x->operand(), tmp, NULL);
__ idiv(left_arg->result(), right_arg->result(), x->operand(), ill, NULL);
}
} else if (x->op() == Bytecodes::_iadd || x->op() == Bytecodes::_isub) {

View File

@ -822,6 +822,15 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset,
return stub_start_addr;
}
void MacroAssembler::c2bool(Register x) {
// implements x == 0 ? 0 : 1
// note: must only look at least-significant byte of x
// since C-style booleans are stored in one byte
// only! (was bug)
tst(x, 0xff);
cset(x, Assembler::NE);
}
address MacroAssembler::ic_call(address entry, jint method_index) {
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
// address const_ptr = long_constant((jlong)Universe::non_oop_word());

View File

@ -782,6 +782,9 @@ public:
void resolve_jobject(Register value, Register thread, Register tmp);
// C 'boolean' to Java boolean: x == 0 ? 0 : 1
void c2bool(Register x);
// oop manipulations
void load_klass(Register dst, Register src);
void store_klass(Register dst, Register src);

View File

@ -1924,7 +1924,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
// Unpack native results.
switch (ret_type) {
case T_BOOLEAN: __ ubfx(r0, r0, 0, 8); break;
case T_BOOLEAN: __ c2bool(r0); break;
case T_CHAR : __ ubfx(r0, r0, 0, 16); break;
case T_BYTE : __ sbfx(r0, r0, 0, 8); break;
case T_SHORT : __ sbfx(r0, r0, 0, 16); break;

View File

@ -557,7 +557,7 @@ address TemplateInterpreterGenerator::generate_result_handler_for(
BasicType type) {
address entry = __ pc();
switch (type) {
case T_BOOLEAN: __ uxtb(r0, r0); break;
case T_BOOLEAN: __ c2bool(r0); break;
case T_CHAR : __ uxth(r0, r0); break;
case T_BYTE : __ sxtb(r0, r0); break;
case T_SHORT : __ sxth(r0, r0); break;

View File

@ -3265,7 +3265,9 @@ void LIR_Assembler::align_backward_branch_target() {
}
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
// tmp must be unused
assert(tmp->is_illegal(), "wasting a register if tmp is allocated");
if (left->is_single_cpu()) {
assert (dest->type() == T_INT, "unexpected result type");

View File

@ -2840,7 +2840,9 @@ void LIR_Assembler::emit_delay(LIR_OpDelay* op) {
}
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
// tmp must be unused
assert(tmp->is_illegal(), "wasting a register if tmp is allocated");
assert(left->is_register(), "can only handle registers");
if (left->is_single_cpu()) {

View File

@ -2850,7 +2850,9 @@ void LIR_Assembler::emit_delay(LIR_OpDelay* op) {
ShouldNotCallThis(); // There are no delay slots on ZARCH_64.
}
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
// tmp must be unused
assert(tmp->is_illegal(), "wasting a register if tmp is allocated");
assert(left->is_register(), "can only handle registers");
if (left->is_single_cpu()) {

View File

@ -3024,7 +3024,9 @@ void LIR_Assembler::emit_delay(LIR_OpDelay* op) {
}
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
// tmp must be unused
assert(tmp->is_illegal(), "wasting a register if tmp is allocated");
assert(left->is_register(), "can only handle registers");
if (left->is_single_cpu()) {

File diff suppressed because it is too large Load Diff

View File

@ -2097,6 +2097,7 @@ private:
// Andn packed integers
void pandn(XMMRegister dst, XMMRegister src);
void vpandn(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
// Or packed integers
void por(XMMRegister dst, XMMRegister src);
@ -2134,6 +2135,7 @@ private:
void vextracti32x4(Address dst, XMMRegister src, uint8_t imm8);
void vextracti64x2(XMMRegister dst, XMMRegister src, uint8_t imm8);
void vextracti64x4(XMMRegister dst, XMMRegister src, uint8_t imm8);
void vextracti64x4(Address dst, XMMRegister src, uint8_t imm8);
// vextractf forms
void vextractf128(XMMRegister dst, XMMRegister src, uint8_t imm8);
@ -2144,28 +2146,24 @@ private:
void vextractf64x4(XMMRegister dst, XMMRegister src, uint8_t imm8);
void vextractf64x4(Address dst, XMMRegister src, uint8_t imm8);
// legacy xmm sourced word/dword replicate
void vpbroadcastw(XMMRegister dst, XMMRegister src);
void vpbroadcastd(XMMRegister dst, XMMRegister src);
// xmm/mem sourced byte/word/dword/qword replicate
void evpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastb(XMMRegister dst, Address src, int vector_len);
void evpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastw(XMMRegister dst, Address src, int vector_len);
void evpbroadcastd(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastd(XMMRegister dst, Address src, int vector_len);
void evpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastq(XMMRegister dst, Address src, int vector_len);
void vpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len);
void vpbroadcastb(XMMRegister dst, Address src, int vector_len);
void vpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len);
void vpbroadcastw(XMMRegister dst, Address src, int vector_len);
void vpbroadcastd(XMMRegister dst, XMMRegister src, int vector_len);
void vpbroadcastd(XMMRegister dst, Address src, int vector_len);
void vpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len);
void vpbroadcastq(XMMRegister dst, Address src, int vector_len);
void evbroadcasti64x2(XMMRegister dst, XMMRegister src, int vector_len);
void evbroadcasti64x2(XMMRegister dst, Address src, int vector_len);
// scalar single/double precision replicate
void evpbroadcastss(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastss(XMMRegister dst, Address src, int vector_len);
void evpbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastsd(XMMRegister dst, Address src, int vector_len);
void vpbroadcastss(XMMRegister dst, XMMRegister src, int vector_len);
void vpbroadcastss(XMMRegister dst, Address src, int vector_len);
void vpbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len);
void vpbroadcastsd(XMMRegister dst, Address src, int vector_len);
// gpr sourced byte/word/dword/qword replicate
void evpbroadcastb(XMMRegister dst, Register src, int vector_len);

View File

@ -68,7 +68,6 @@ static jlong *float_signflip_pool = double_quadword(&fp_signmask_pool[3*2], (jl
static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], (jlong)UCONST64(0x8000000000000000), (jlong)UCONST64(0x8000000000000000));
NEEDS_CLEANUP // remove this definitions ?
const Register IC_Klass = rax; // where the IC klass is cached
const Register SYNC_header = rax; // synchronization header
@ -650,7 +649,7 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod
case T_FLOAT: {
if (dest->is_single_xmm()) {
if (c->is_zero_float()) {
if (LP64_ONLY(UseAVX < 2 &&) c->is_zero_float()) {
__ xorps(dest->as_xmm_float_reg(), dest->as_xmm_float_reg());
} else {
__ movflt(dest->as_xmm_float_reg(),
@ -672,7 +671,7 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod
case T_DOUBLE: {
if (dest->is_double_xmm()) {
if (c->is_zero_double()) {
if (LP64_ONLY(UseAVX < 2 &&) c->is_zero_double()) {
__ xorpd(dest->as_xmm_double_reg(), dest->as_xmm_double_reg());
} else {
__ movdbl(dest->as_xmm_double_reg(),
@ -2395,16 +2394,24 @@ void LIR_Assembler::arith_fpu_implementation(LIR_Code code, int left_index, int
}
void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr unused, LIR_Opr dest, LIR_Op* op) {
void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr tmp, LIR_Opr dest, LIR_Op* op) {
if (value->is_double_xmm()) {
switch(code) {
case lir_abs :
{
if (dest->as_xmm_double_reg() != value->as_xmm_double_reg()) {
__ movdbl(dest->as_xmm_double_reg(), value->as_xmm_double_reg());
#ifdef _LP64
if (UseAVX > 2 && !VM_Version::supports_avx512vl()) {
assert(tmp->is_valid(), "need temporary");
__ vpandn(dest->as_xmm_double_reg(), tmp->as_xmm_double_reg(), value->as_xmm_double_reg(), 2);
} else {
#endif
if (dest->as_xmm_double_reg() != value->as_xmm_double_reg()) {
__ movdbl(dest->as_xmm_double_reg(), value->as_xmm_double_reg());
}
assert(!tmp->is_valid(), "do not need temporary");
__ andpd(dest->as_xmm_double_reg(),
ExternalAddress((address)double_signmask_pool));
}
__ andpd(dest->as_xmm_double_reg(),
ExternalAddress((address)double_signmask_pool));
}
break;
@ -3734,7 +3741,7 @@ void LIR_Assembler::align_backward_branch_target() {
}
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) {
if (left->is_single_cpu()) {
__ negl(left->as_register());
move_regs(left->as_register(), dest->as_register());
@ -3759,24 +3766,36 @@ void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) {
#endif // _LP64
} else if (dest->is_single_xmm()) {
if (left->as_xmm_float_reg() != dest->as_xmm_float_reg()) {
__ movflt(dest->as_xmm_float_reg(), left->as_xmm_float_reg());
#ifdef _LP64
if (UseAVX > 2 && !VM_Version::supports_avx512vl()) {
assert(tmp->is_valid(), "need temporary");
assert_different_registers(left->as_xmm_float_reg(), tmp->as_xmm_float_reg());
__ vpxor(dest->as_xmm_float_reg(), tmp->as_xmm_float_reg(), left->as_xmm_float_reg(), 2);
}
if (UseAVX > 0) {
__ vnegatess(dest->as_xmm_float_reg(), dest->as_xmm_float_reg(),
ExternalAddress((address)float_signflip_pool));
} else {
else
#endif
{
assert(!tmp->is_valid(), "do not need temporary");
if (left->as_xmm_float_reg() != dest->as_xmm_float_reg()) {
__ movflt(dest->as_xmm_float_reg(), left->as_xmm_float_reg());
}
__ xorps(dest->as_xmm_float_reg(),
ExternalAddress((address)float_signflip_pool));
}
} else if (dest->is_double_xmm()) {
if (left->as_xmm_double_reg() != dest->as_xmm_double_reg()) {
__ movdbl(dest->as_xmm_double_reg(), left->as_xmm_double_reg());
#ifdef _LP64
if (UseAVX > 2 && !VM_Version::supports_avx512vl()) {
assert(tmp->is_valid(), "need temporary");
assert_different_registers(left->as_xmm_double_reg(), tmp->as_xmm_double_reg());
__ vpxor(dest->as_xmm_double_reg(), tmp->as_xmm_double_reg(), left->as_xmm_double_reg(), 2);
}
if (UseAVX > 0) {
__ vnegatesd(dest->as_xmm_double_reg(), dest->as_xmm_double_reg(),
ExternalAddress((address)double_signflip_pool));
} else {
else
#endif
{
assert(!tmp->is_valid(), "do not need temporary");
if (left->as_xmm_double_reg() != dest->as_xmm_double_reg()) {
__ movdbl(dest->as_xmm_double_reg(), left->as_xmm_double_reg());
}
__ xorpd(dest->as_xmm_double_reg(),
ExternalAddress((address)double_signflip_pool));
}

View File

@ -320,7 +320,21 @@ void LIRGenerator::do_NegateOp(NegateOp* x) {
value.set_destroys_register();
value.load_item();
LIR_Opr reg = rlock(x);
__ negate(value.result(), reg);
LIR_Opr tmp = LIR_OprFact::illegalOpr;
#ifdef _LP64
if (UseAVX > 2 && !VM_Version::supports_avx512vl()) {
if (x->type()->tag() == doubleTag) {
tmp = new_register(T_DOUBLE);
__ move(LIR_OprFact::doubleConst(-0.0), tmp);
}
else if (x->type()->tag() == floatTag) {
tmp = new_register(T_FLOAT);
__ move(LIR_OprFact::floatConst(-0.0), tmp);
}
}
#endif
__ negate(value.result(), reg, tmp);
set_result(x, round_item(reg));
}
@ -748,8 +762,17 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
LIR_Opr calc_input = value.result();
LIR_Opr calc_result = rlock_result(x);
LIR_Opr tmp = LIR_OprFact::illegalOpr;
#ifdef _LP64
if (UseAVX > 2 && (!VM_Version::supports_avx512vl()) &&
(x->id() == vmIntrinsics::_dabs)) {
tmp = new_register(T_DOUBLE);
__ move(LIR_OprFact::doubleConst(-0.0), tmp);
}
#endif
switch(x->id()) {
case vmIntrinsics::_dabs: __ abs (calc_input, calc_result, LIR_OprFact::illegalOpr); break;
case vmIntrinsics::_dabs: __ abs (calc_input, calc_result, tmp); break;
case vmIntrinsics::_dsqrt: __ sqrt (calc_input, calc_result, LIR_OprFact::illegalOpr); break;
default: ShouldNotReachHere();
}

View File

@ -119,7 +119,7 @@ define_pd_global(bool, ThreadLocalHandshakes, false);
product(bool, UseStoreImmI16, true, \
"Use store immediate 16-bits value instruction on x86") \
\
product(intx, UseAVX, 2, \
product(intx, UseAVX, 3, \
"Highest supported AVX instructions set on x86/x64") \
range(0, 99) \
\

File diff suppressed because it is too large Load Diff

View File

@ -482,10 +482,6 @@ class MacroAssembler: public Assembler {
// from register xmm0. Otherwise, the value is stored from the FPU stack.
void store_double(Address dst);
// Save/restore ZMM (512bit) register on stack.
void push_zmm(XMMRegister reg);
void pop_zmm(XMMRegister reg);
// pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
void push_fTOS();
@ -1214,9 +1210,11 @@ public:
void vpand(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { Assembler::vpand(dst, nds, src, vector_len); }
void vpand(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len);
void vpbroadcastw(XMMRegister dst, XMMRegister src);
void vpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len);
void vpbroadcastw(XMMRegister dst, Address src, int vector_len) { Assembler::vpbroadcastw(dst, src, vector_len); }
void vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void vpmovzxbw(XMMRegister dst, Address src, int vector_len);

View File

@ -403,7 +403,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ movdl(xmm0, rcx);
__ movl(rcx, 0xffff);
__ kmovwl(k1, rcx);
__ evpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
__ vpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
__ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit);
#ifdef _LP64
__ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit);
@ -885,7 +885,7 @@ void VM_Version::get_processor_features() {
FLAG_SET_DEFAULT(UseSHA, false);
}
if (supports_sha() && UseSHA) {
if (supports_sha() && supports_sse4_1() && UseSHA) {
if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
}
@ -894,7 +894,7 @@ void VM_Version::get_processor_features() {
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
}
if (UseSHA) {
if (supports_sse4_1() && UseSHA) {
if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
}

View File

@ -816,7 +816,10 @@ public:
static bool supports_avx512cd() { return (_features & CPU_AVX512CD) != 0; }
static bool supports_avx512bw() { return (_features & CPU_AVX512BW) != 0; }
static bool supports_avx512vl() { return (_features & CPU_AVX512VL) != 0; }
static bool supports_avx512vlbw() { return (supports_avx512bw() && supports_avx512vl()); }
static bool supports_avx512vlbw() { return (supports_evex() && supports_avx512bw() && supports_avx512vl()); }
static bool supports_avx512vldq() { return (supports_evex() && supports_avx512dq() && supports_avx512vl()); }
static bool supports_avx512vlbwdq() { return (supports_evex() && supports_avx512vl() &&
supports_avx512bw() && supports_avx512dq()); }
static bool supports_avx512novl() { return (supports_evex() && !supports_avx512vl()); }
static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); }
static bool supports_avx256only() { return (supports_avx2() && !supports_evex()); }

File diff suppressed because it is too large Load Diff

View File

@ -4101,6 +4101,15 @@ operand regF() %{
interface(REG_INTER);
%}
// Float register operands
operand vlRegF() %{
constraint(ALLOC_IN_RC(float_reg_vl));
match(RegF);
format %{ %}
interface(REG_INTER);
%}
// XMM Double register operands
operand regD() %{
predicate( UseSSE>=2 );
@ -4110,6 +4119,15 @@ operand regD() %{
interface(REG_INTER);
%}
// Double register operands
operand vlRegD() %{
constraint(ALLOC_IN_RC(double_reg_vl));
match(RegD);
format %{ %}
interface(REG_INTER);
%}
// Vectors : note, we use legacy registers to avoid extra (unneeded in 32-bit VM)
// runtime code generation via reg_class_dynamic.
operand vecS() %{
@ -4120,6 +4138,14 @@ operand vecS() %{
interface(REG_INTER);
%}
operand legVecS() %{
constraint(ALLOC_IN_RC(vectors_reg_legacy));
match(VecS);
format %{ %}
interface(REG_INTER);
%}
operand vecD() %{
constraint(ALLOC_IN_RC(vectord_reg_legacy));
match(VecD);
@ -4128,6 +4154,14 @@ operand vecD() %{
interface(REG_INTER);
%}
operand legVecD() %{
constraint(ALLOC_IN_RC(vectord_reg_legacy));
match(VecD);
format %{ %}
interface(REG_INTER);
%}
operand vecX() %{
constraint(ALLOC_IN_RC(vectorx_reg_legacy));
match(VecX);
@ -4136,6 +4170,14 @@ operand vecX() %{
interface(REG_INTER);
%}
operand legVecX() %{
constraint(ALLOC_IN_RC(vectorx_reg_legacy));
match(VecX);
format %{ %}
interface(REG_INTER);
%}
operand vecY() %{
constraint(ALLOC_IN_RC(vectory_reg_legacy));
match(VecY);
@ -4144,6 +4186,14 @@ operand vecY() %{
interface(REG_INTER);
%}
operand legVecY() %{
constraint(ALLOC_IN_RC(vectory_reg_legacy));
match(VecY);
format %{ %}
interface(REG_INTER);
%}
//----------Memory Operands----------------------------------------------------
// Direct Memory Operand
operand direct(immP addr) %{
@ -6515,6 +6565,26 @@ instruct storeD(memory mem, regD src) %{
ins_pipe( pipe_slow );
%}
// Load Double
instruct MoveD2VL(vlRegD dst, regD src) %{
match(Set dst src);
format %{ "movsd $dst,$src\t! load double (8 bytes)" %}
ins_encode %{
__ movdbl($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Load Double
instruct MoveVL2D(regD dst, vlRegD src) %{
match(Set dst src);
format %{ "movsd $dst,$src\t! load double (8 bytes)" %}
ins_encode %{
__ movdbl($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Store XMM register to memory (single-precision floating point)
// MOVSS instruction
instruct storeF(memory mem, regF src) %{
@ -6528,6 +6598,26 @@ instruct storeF(memory mem, regF src) %{
ins_pipe( pipe_slow );
%}
// Load Float
instruct MoveF2VL(vlRegF dst, regF src) %{
match(Set dst src);
format %{ "movss $dst,$src\t! load float (4 bytes)" %}
ins_encode %{
__ movflt($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Load Float
instruct MoveVL2F(regF dst, vlRegF src) %{
match(Set dst src);
format %{ "movss $dst,$src\t! load float (4 bytes)" %}
ins_encode %{
__ movflt($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Store Float
instruct storeFPR( memory mem, regFPR1 src) %{
predicate(UseSSE==0);

View File

@ -3656,6 +3656,15 @@ operand regF() %{
interface(REG_INTER);
%}
// Float register operands
operand vlRegF() %{
constraint(ALLOC_IN_RC(float_reg_vl));
match(RegF);
format %{ %}
interface(REG_INTER);
%}
// Double register operands
operand regD() %{
constraint(ALLOC_IN_RC(double_reg));
@ -3665,9 +3674,27 @@ operand regD() %{
interface(REG_INTER);
%}
// Double register operands
operand vlRegD() %{
constraint(ALLOC_IN_RC(double_reg_vl));
match(RegD);
format %{ %}
interface(REG_INTER);
%}
// Vectors
operand vecS() %{
constraint(ALLOC_IN_RC(vectors_reg));
constraint(ALLOC_IN_RC(vectors_reg_vlbwdq));
match(VecS);
format %{ %}
interface(REG_INTER);
%}
// Vectors
operand legVecS() %{
constraint(ALLOC_IN_RC(vectors_reg_legacy));
match(VecS);
format %{ %}
@ -3675,7 +3702,15 @@ operand vecS() %{
%}
operand vecD() %{
constraint(ALLOC_IN_RC(vectord_reg));
constraint(ALLOC_IN_RC(vectord_reg_vlbwdq));
match(VecD);
format %{ %}
interface(REG_INTER);
%}
operand legVecD() %{
constraint(ALLOC_IN_RC(vectord_reg_legacy));
match(VecD);
format %{ %}
@ -3683,7 +3718,15 @@ operand vecD() %{
%}
operand vecX() %{
constraint(ALLOC_IN_RC(vectorx_reg));
constraint(ALLOC_IN_RC(vectorx_reg_vlbwdq));
match(VecX);
format %{ %}
interface(REG_INTER);
%}
operand legVecX() %{
constraint(ALLOC_IN_RC(vectorx_reg_legacy));
match(VecX);
format %{ %}
@ -3691,7 +3734,15 @@ operand vecX() %{
%}
operand vecY() %{
constraint(ALLOC_IN_RC(vectory_reg));
constraint(ALLOC_IN_RC(vectory_reg_vlbwdq));
match(VecY);
format %{ %}
interface(REG_INTER);
%}
operand legVecY() %{
constraint(ALLOC_IN_RC(vectory_reg_legacy));
match(VecY);
format %{ %}
@ -5287,6 +5338,26 @@ instruct loadF(regF dst, memory mem)
ins_pipe(pipe_slow); // XXX
%}
// Load Float
instruct MoveF2VL(vlRegF dst, regF src) %{
match(Set dst src);
format %{ "movss $dst,$src\t! load float (4 bytes)" %}
ins_encode %{
__ movflt($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Load Float
instruct MoveVL2F(regF dst, vlRegF src) %{
match(Set dst src);
format %{ "movss $dst,$src\t! load float (4 bytes)" %}
ins_encode %{
__ movflt($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Load Double
instruct loadD_partial(regD dst, memory mem)
%{
@ -5314,6 +5385,26 @@ instruct loadD(regD dst, memory mem)
ins_pipe(pipe_slow); // XXX
%}
// Load Double
instruct MoveD2VL(vlRegD dst, regD src) %{
match(Set dst src);
format %{ "movsd $dst,$src\t! load double (8 bytes)" %}
ins_encode %{
__ movdbl($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Load Double
instruct MoveVL2D(regD dst, vlRegD src) %{
match(Set dst src);
format %{ "movsd $dst,$src\t! load double (8 bytes)" %}
ins_encode %{
__ movdbl($dst$$XMMRegister, $src$$XMMRegister);
%}
ins_pipe( fpu_reg_reg );
%}
// Load Effective Address
instruct leaP8(rRegP dst, indOffset8 mem)
%{
@ -10858,7 +10949,7 @@ instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
%}
instruct string_compareL(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2,
rax_RegI result, regD tmp1, rFlagsReg cr)
rax_RegI result, legVecS tmp1, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
@ -10874,7 +10965,7 @@ instruct string_compareL(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI c
%}
instruct string_compareU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2,
rax_RegI result, regD tmp1, rFlagsReg cr)
rax_RegI result, legVecS tmp1, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
@ -10890,7 +10981,7 @@ instruct string_compareU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI c
%}
instruct string_compareLU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2,
rax_RegI result, regD tmp1, rFlagsReg cr)
rax_RegI result, legVecS tmp1, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
@ -10906,7 +10997,7 @@ instruct string_compareLU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI
%}
instruct string_compareUL(rsi_RegP str1, rdx_RegI cnt1, rdi_RegP str2, rcx_RegI cnt2,
rax_RegI result, regD tmp1, rFlagsReg cr)
rax_RegI result, legVecS tmp1, rFlagsReg cr)
%{
predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
@ -10923,7 +11014,7 @@ instruct string_compareUL(rsi_RegP str1, rdx_RegI cnt1, rdi_RegP str2, rcx_RegI
// fast search of substring with known size.
instruct string_indexof_conL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2,
rbx_RegI result, regD vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr)
rbx_RegI result, legVecS vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
@ -10952,7 +11043,7 @@ instruct string_indexof_conL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI i
// fast search of substring with known size.
instruct string_indexof_conU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2,
rbx_RegI result, regD vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr)
rbx_RegI result, legVecS vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
@ -10981,7 +11072,7 @@ instruct string_indexof_conU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI i
// fast search of substring with known size.
instruct string_indexof_conUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2,
rbx_RegI result, regD vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr)
rbx_RegI result, legVecS vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
@ -11009,7 +11100,7 @@ instruct string_indexof_conUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI
%}
instruct string_indexofL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2,
rbx_RegI result, regD vec, rcx_RegI tmp, rFlagsReg cr)
rbx_RegI result, legVecS vec, rcx_RegI tmp, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
@ -11026,7 +11117,7 @@ instruct string_indexofL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI c
%}
instruct string_indexofU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2,
rbx_RegI result, regD vec, rcx_RegI tmp, rFlagsReg cr)
rbx_RegI result, legVecS vec, rcx_RegI tmp, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
@ -11043,7 +11134,7 @@ instruct string_indexofU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI c
%}
instruct string_indexofUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2,
rbx_RegI result, regD vec, rcx_RegI tmp, rFlagsReg cr)
rbx_RegI result, legVecS vec, rcx_RegI tmp, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
@ -11060,7 +11151,7 @@ instruct string_indexofUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI
%}
instruct string_indexofU_char(rdi_RegP str1, rdx_RegI cnt1, rax_RegI ch,
rbx_RegI result, regD vec1, regD vec2, regD vec3, rcx_RegI tmp, rFlagsReg cr)
rbx_RegI result, legVecS vec1, legVecS vec2, legVecS vec3, rcx_RegI tmp, rFlagsReg cr)
%{
predicate(UseSSE42Intrinsics);
match(Set result (StrIndexOfChar (Binary str1 cnt1) ch));
@ -11075,7 +11166,7 @@ instruct string_indexofU_char(rdi_RegP str1, rdx_RegI cnt1, rax_RegI ch,
// fast string equals
instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result,
regD tmp1, regD tmp2, rbx_RegI tmp3, rFlagsReg cr)
legVecS tmp1, legVecS tmp2, rbx_RegI tmp3, rFlagsReg cr)
%{
match(Set result (StrEquals (Binary str1 str2) cnt));
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr);
@ -11091,7 +11182,7 @@ instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI resu
// fast array equals
instruct array_equalsB(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
regD tmp1, regD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr)
legVecS tmp1, legVecS tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr)
%{
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL);
match(Set result (AryEq ary1 ary2));
@ -11107,7 +11198,7 @@ instruct array_equalsB(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
%}
instruct array_equalsC(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
regD tmp1, regD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr)
legVecS tmp1, legVecS tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr)
%{
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
match(Set result (AryEq ary1 ary2));
@ -11123,7 +11214,7 @@ instruct array_equalsC(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
%}
instruct has_negatives(rsi_RegP ary1, rcx_RegI len, rax_RegI result,
regD tmp1, regD tmp2, rbx_RegI tmp3, rFlagsReg cr)
legVecS tmp1, legVecS tmp2, rbx_RegI tmp3, rFlagsReg cr)
%{
match(Set result (HasNegatives ary1 len));
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr);
@ -11138,7 +11229,7 @@ instruct has_negatives(rsi_RegP ary1, rcx_RegI len, rax_RegI result,
%}
// fast char[] to byte[] compression
instruct string_compress(rsi_RegP src, rdi_RegP dst, rdx_RegI len, regD tmp1, regD tmp2, regD tmp3, regD tmp4,
instruct string_compress(rsi_RegP src, rdi_RegP dst, rdx_RegI len, legVecS tmp1, legVecS tmp2, legVecS tmp3, legVecS tmp4,
rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{
match(Set result (StrCompressedCopy src (Binary dst len)));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr);
@ -11154,7 +11245,7 @@ instruct string_compress(rsi_RegP src, rdi_RegP dst, rdx_RegI len, regD tmp1, re
// fast byte[] to char[] inflation
instruct string_inflate(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_RegI len,
regD tmp1, rcx_RegI tmp2, rFlagsReg cr) %{
legVecS tmp1, rcx_RegI tmp2, rFlagsReg cr) %{
match(Set dummy (StrInflatedCopy src (Binary dst len)));
effect(TEMP tmp1, TEMP tmp2, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr);
@ -11168,7 +11259,7 @@ instruct string_inflate(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_RegI len
// encode char[] to byte[] in ISO_8859_1
instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len,
regD tmp1, regD tmp2, regD tmp3, regD tmp4,
legVecS tmp1, legVecS tmp2, legVecS tmp3, legVecS tmp4,
rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{
match(Set result (EncodeISOArray src (Binary dst len)));
effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr);

View File

@ -472,7 +472,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
case lir_pop: // input always valid, result and info always invalid
case lir_return: // input always valid, result and info always invalid
case lir_leal: // input and result always valid, info always invalid
case lir_neg: // input and result always valid, info always invalid
case lir_monaddr: // input and result always valid, info always invalid
case lir_null_check: // input and info always valid, result always invalid
case lir_move: // input and result always valid, may have info
@ -580,6 +579,7 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
case lir_rem:
case lir_sqrt:
case lir_abs:
case lir_neg:
case lir_logic_and:
case lir_logic_or:
case lir_logic_xor:
@ -1662,7 +1662,6 @@ const char * LIR_Op::name() const {
case lir_null_check: s = "null_check"; break;
case lir_return: s = "return"; break;
case lir_safepoint: s = "safepoint"; break;
case lir_neg: s = "neg"; break;
case lir_leal: s = "leal"; break;
case lir_branch: s = "branch"; break;
case lir_cond_float_branch: s = "flt_cond_br"; break;
@ -1690,6 +1689,7 @@ const char * LIR_Op::name() const {
case lir_div_strictfp: s = "div_strictfp"; break;
case lir_rem: s = "rem"; break;
case lir_abs: s = "abs"; break;
case lir_neg: s = "neg"; break;
case lir_sqrt: s = "sqrt"; break;
case lir_logic_and: s = "logic_and"; break;
case lir_logic_or: s = "logic_or"; break;

View File

@ -911,7 +911,6 @@ enum LIR_Code {
, lir_null_check
, lir_return
, lir_leal
, lir_neg
, lir_branch
, lir_cond_float_branch
, lir_move
@ -939,6 +938,7 @@ enum LIR_Code {
, lir_rem
, lir_sqrt
, lir_abs
, lir_neg
, lir_tan
, lir_log10
, lir_logic_and
@ -2075,7 +2075,6 @@ class LIR_List: public CompilationResourceObj {
void branch_destination(Label* lbl) { append(new LIR_OpLabel(lbl)); }
void negate(LIR_Opr from, LIR_Opr to) { append(new LIR_Op1(lir_neg, from, to)); }
void leal(LIR_Opr from, LIR_Opr result_reg, LIR_PatchCode patch_code = lir_patch_none, CodeEmitInfo* info = NULL) { append(new LIR_Op1(lir_leal, from, result_reg, T_ILLEGAL, patch_code, info)); }
// result is a stack location for old backend and vreg for UseLinearScan
@ -2159,6 +2158,7 @@ class LIR_List: public CompilationResourceObj {
LIR_Opr t1, LIR_Opr t2, LIR_Opr result = LIR_OprFact::illegalOpr);
void abs (LIR_Opr from, LIR_Opr to, LIR_Opr tmp) { append(new LIR_Op2(lir_abs , from, tmp, to)); }
void negate(LIR_Opr from, LIR_Opr to, LIR_Opr tmp = LIR_OprFact::illegalOpr) { append(new LIR_Op2(lir_neg, from, tmp, to)); }
void sqrt(LIR_Opr from, LIR_Opr to, LIR_Opr tmp) { append(new LIR_Op2(lir_sqrt, from, tmp, to)); }
void fmad(LIR_Opr from, LIR_Opr from1, LIR_Opr from2, LIR_Opr to) { append(new LIR_Op3(lir_fmad, from, from1, from2, to)); }
void fmaf(LIR_Opr from, LIR_Opr from1, LIR_Opr from2, LIR_Opr to) { append(new LIR_Op3(lir_fmaf, from, from1, from2, to)); }

View File

@ -554,10 +554,6 @@ void LIR_Assembler::emit_op1(LIR_Op1* op) {
pop(op->in_opr());
break;
case lir_neg:
negate(op->in_opr(), op->result_opr());
break;
case lir_leal:
leal(op->in_opr(), op->result_opr(), op->patch_code(), op->info());
break;
@ -750,6 +746,10 @@ void LIR_Assembler::emit_op2(LIR_Op2* op) {
intrinsic_op(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op);
break;
case lir_neg:
negate(op->in_opr1(), op->result_opr(), op->in_opr2());
break;
case lir_logic_and:
case lir_logic_or:
case lir_logic_xor:

View File

@ -239,7 +239,7 @@ class LIR_Assembler: public CompilationResourceObj {
void align_backward_branch_target();
void align_call(LIR_Code code);
void negate(LIR_Opr left, LIR_Opr dest);
void negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp = LIR_OprFact::illegalOpr);
void leal(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info);
void rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info);

View File

@ -605,9 +605,10 @@ void ClassLoaderData::unload() {
// if they are not already on the _klasses list.
free_deallocate_list_C_heap_structures();
// Tell serviceability tools these classes are unloading
// Clean up class dependencies and tell serviceability tools
// these classes are unloading. Must be called
// after erroneous classes are released.
classes_do(InstanceKlass::notify_unload_class);
classes_do(InstanceKlass::unload_class);
// Clean up global class iterator for compiler
static_klass_iterator.adjust_saved_class(this);

View File

@ -218,18 +218,6 @@ int DependencyContext::remove_all_dependents() {
return marked;
}
void DependencyContext::wipe() {
assert_locked_or_safepoint(CodeCache_lock);
nmethodBucket* b = dependencies();
set_dependencies(NULL);
set_has_stale_entries(false);
while (b != NULL) {
nmethodBucket* next = b->next();
delete b;
b = next;
}
}
#ifndef PRODUCT
void DependencyContext::print_dependent_nmethods(bool verbose) {
int idx = 0;

View File

@ -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
@ -141,10 +141,6 @@ class DependencyContext : public StackObj {
void expunge_stale_entries();
// Unsafe deallocation of nmethodBuckets. Used in IK::release_C_heap_structures
// to clean up the context possibly containing live entries pointing to unloaded nmethods.
void wipe();
#ifndef PRODUCT
void print_dependent_nmethods(bool verbose);
bool is_dependent_nmethod(nmethod* nm);

View File

@ -3169,18 +3169,24 @@ void G1CollectedHeap::preserve_mark_during_evac_failure(uint worker_id, oop obj,
}
bool G1ParEvacuateFollowersClosure::offer_termination() {
EventGCPhaseParallel event;
G1ParScanThreadState* const pss = par_scan_state();
start_term_time();
const bool res = terminator()->offer_termination();
end_term_time();
event.commit(GCId::current(), pss->worker_id(), G1GCPhaseTimes::phase_name(G1GCPhaseTimes::Termination));
return res;
}
void G1ParEvacuateFollowersClosure::do_void() {
EventGCPhaseParallel event;
G1ParScanThreadState* const pss = par_scan_state();
pss->trim_queue();
event.commit(GCId::current(), pss->worker_id(), G1GCPhaseTimes::phase_name(G1GCPhaseTimes::ObjCopy));
do {
EventGCPhaseParallel event;
pss->steal_and_trim_queue(queues());
event.commit(GCId::current(), pss->worker_id(), G1GCPhaseTimes::phase_name(G1GCPhaseTimes::ObjCopy));
} while (!offer_termination());
}
@ -4050,6 +4056,7 @@ public:
break;
}
EventGCPhaseParallel event;
double start_time = os::elapsedTime();
end = MIN2(end, _num_work_items);
@ -4064,9 +4071,11 @@ public:
if (is_young) {
young_time += time_taken;
has_young_time = true;
event.commit(GCId::current(), worker_id, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::YoungFreeCSet));
} else {
non_young_time += time_taken;
has_non_young_time = true;
event.commit(GCId::current(), worker_id, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::NonYoungFreeCSet));
}
start_time = end_time;
}

View File

@ -465,6 +465,48 @@ void G1GCPhaseTimes::print() {
}
}
const char* G1GCPhaseTimes::phase_name(GCParPhases phase) {
static const char* names[] = {
"GCWorkerStart",
"ExtRootScan",
"ThreadRoots",
"StringTableRoots",
"UniverseRoots",
"JNIRoots",
"ObjectSynchronizerRoots",
"ManagementRoots",
"SystemDictionaryRoots",
"CLDGRoots",
"JVMTIRoots",
"CMRefRoots",
"WaitForStrongCLD",
"WeakCLDRoots",
"SATBFiltering",
"UpdateRS",
"ScanHCC",
"ScanRS",
"CodeRoots",
#if INCLUDE_AOT
"AOTCodeRoots",
#endif
"ObjCopy",
"Termination",
"Other",
"GCWorkerTotal",
"GCWorkerEnd",
"StringDedupQueueFixup",
"StringDedupTableFixup",
"RedirtyCards",
"YoungFreeCSet",
"NonYoungFreeCSet"
//GCParPhasesSentinel only used to tell end of enum
};
STATIC_ASSERT(ARRAY_SIZE(names) == G1GCPhaseTimes::GCParPhasesSentinel); // GCParPhases enum and corresponding string array should have the same "length", this tries to assert it
return names[phase];
}
G1EvacPhaseWithTrimTimeTracker::G1EvacPhaseWithTrimTimeTracker(G1ParScanThreadState* pss, Tickspan& total_time, Tickspan& trim_time) :
_pss(pss),
_start(Ticks::now()),
@ -490,7 +532,7 @@ void G1EvacPhaseWithTrimTimeTracker::stop() {
}
G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id) :
_start_time(), _phase(phase), _phase_times(phase_times), _worker_id(worker_id) {
_start_time(), _phase(phase), _phase_times(phase_times), _worker_id(worker_id), _event() {
if (_phase_times != NULL) {
_start_time = Ticks::now();
}
@ -499,6 +541,7 @@ G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times,
G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
if (_phase_times != NULL) {
_phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds());
_event.commit(GCId::current(), _worker_id, G1GCPhaseTimes::phase_name(_phase));
}
}

View File

@ -27,6 +27,7 @@
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
#include "gc/shared/weakProcessorPhaseTimes.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/logLevel.hpp"
#include "memory/allocation.hpp"
#include "utilities/macros.hpp"
@ -190,6 +191,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads);
void note_gc_start();
void print();
static const char* phase_name(GCParPhases phase);
// record the time a phase took in seconds
void record_time_secs(GCParPhases phase, uint worker_i, double secs);
@ -385,6 +387,7 @@ protected:
G1GCPhaseTimes::GCParPhases _phase;
G1GCPhaseTimes* _phase_times;
uint _worker_id;
EventGCPhaseParallel _event;
public:
G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id);
virtual ~G1GCParPhaseTimesTracker();

View File

@ -40,6 +40,7 @@
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/suspendibleThreadSet.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/iterator.hpp"
#include "memory/resourceArea.hpp"
#include "oops/access.inline.hpp"
@ -339,6 +340,7 @@ void G1ScanRSForRegionClosure::scan_card(MemRegion mr, uint region_idx_for_card)
}
void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) {
EventGCPhaseParallel event;
uint const region_idx = r->hrm_index();
if (_scan_state->claim_iter(region_idx)) {
@ -392,10 +394,13 @@ void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) {
scan_card(mr, region_idx_for_card);
}
event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::ScanRS));
}
void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) {
EventGCPhaseParallel event;
r->strong_code_roots_do(_pss->closures()->weak_codeblobs());
event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::CodeRoots));
}
bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) {

View File

@ -310,7 +310,7 @@ void C2Access::fixup_decorators() {
//--------------------------- atomic operations---------------------------------
static void pin_atomic_op(C2AtomicAccess& access) {
void BarrierSetC2::pin_atomic_op(C2AtomicAccess& access) const {
if (!access.needs_pinning()) {
return;
}

View File

@ -76,14 +76,12 @@ public:
// This class wraps a node and a pointer type.
class C2AccessValuePtr: public C2AccessValue {
int _alias_idx;
public:
C2AccessValuePtr(Node* node, const TypePtr* type) :
C2AccessValue(node, reinterpret_cast<const Type*>(type)) {}
const TypePtr* type() const { return reinterpret_cast<const TypePtr*>(_type); }
int alias_idx() const { return _alias_idx; }
};
// This class wraps a bunch of context parameters thare are passed around in the
@ -175,6 +173,7 @@ protected:
Node* new_val, const Type* value_type) const;
virtual Node* atomic_xchg_at_resolved(C2AtomicAccess& access, Node* new_val, const Type* val_type) const;
virtual Node* atomic_add_at_resolved(C2AtomicAccess& access, Node* new_val, const Type* val_type) const;
void pin_atomic_op(C2AtomicAccess& access) const;
public:
// This is the entry-point for the backend to perform accesses through the Access API.

View File

@ -435,6 +435,13 @@
<Field type="string" name="name" label="Name" />
</Event>
<Event name="GCPhaseParallel" category="Java Virtual Machine, GC, Phases" label="GC Phase Parallel"
startTime="true" thread="true" description="GC phases for parallel workers">
<Field type="uint" name="gcId" label="GC Identifier" relation="GcId"/>
<Field type="uint" name="gcWorkerId" label="GC Worker Identifier" />
<Field type="string" name="name" label="Name" />
</Event>
<Event name="AllocationRequiringGC" category="Java Virtual Machine, GC, Detailed" label="Allocation Requiring GC" thread="true" stackTrace="true"
startTime="false">
<Field type="uint" name="gcId" label="Pending GC Identifier" relation="GcId" />

View File

@ -2417,7 +2417,10 @@ static void clear_all_breakpoints(Method* m) {
}
#endif
void InstanceKlass::notify_unload_class(InstanceKlass* ik) {
void InstanceKlass::unload_class(InstanceKlass* ik) {
// Release dependencies.
ik->dependencies().remove_all_dependents();
// notify the debugger
if (JvmtiExport::should_post_class_unload()) {
JvmtiExport::post_class_unload(ik);
@ -2462,16 +2465,8 @@ void InstanceKlass::release_C_heap_structures() {
FreeHeap(jmeths);
}
// Release dependencies.
// It is desirable to use DC::remove_all_dependents() here, but, unfortunately,
// it is not safe (see JDK-8143408). The problem is that the klass dependency
// context can contain live dependencies, since there's a race between nmethod &
// klass unloading. If the klass is dead when nmethod unloading happens, relevant
// dependencies aren't removed from the context associated with the class (see
// nmethod::flush_dependencies). It ends up during klass unloading as seemingly
// live dependencies pointing to unloaded nmethods and causes a crash in
// DC::remove_all_dependents() when it touches unloaded nmethod.
dependencies().wipe();
assert(_dep_context == DependencyContext::EMPTY,
"dependencies should already be cleaned");
#if INCLUDE_JVMTI
// Deallocate breakpoint records

View File

@ -1180,7 +1180,7 @@ public:
bool on_stack() const { return _constants->on_stack(); }
// callbacks for actions during class unloading
static void notify_unload_class(InstanceKlass* ik);
static void unload_class(InstanceKlass* ik);
static void release_C_heap_structures(InstanceKlass* ik);
// Naming

View File

@ -605,7 +605,7 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) {
Node *adr = basic_plus_adr(ex_node, ex_node, offset);
const TypeOopPtr* val_type = TypeOopPtr::make_from_klass(env()->String_klass());
Node *store = access_store_at(control(), ex_node, adr, adr_typ, null(), val_type, T_OBJECT, IN_HEAP);
Node *store = access_store_at(ex_node, adr, adr_typ, null(), val_type, T_OBJECT, IN_HEAP);
add_exception_state(make_exception_state(ex_node));
return;
@ -1544,8 +1544,7 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
return st;
}
Node* GraphKit::access_store_at(Node* ctl,
Node* obj,
Node* GraphKit::access_store_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
Node* val,
@ -1559,7 +1558,6 @@ Node* GraphKit::access_store_at(Node* ctl,
val = _gvn.makecon(TypePtr::NULL_PTR);
}
set_control(ctl);
if (stopped()) {
return top(); // Dead path ?
}
@ -1612,8 +1610,7 @@ Node* GraphKit::access_load(Node* adr, // actual adress to load val at
}
}
Node* GraphKit::access_atomic_cmpxchg_val_at(Node* ctl,
Node* obj,
Node* GraphKit::access_atomic_cmpxchg_val_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -1622,7 +1619,6 @@ Node* GraphKit::access_atomic_cmpxchg_val_at(Node* ctl,
const Type* value_type,
BasicType bt,
DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS,
bt, obj, addr, alias_idx);
@ -1633,8 +1629,7 @@ Node* GraphKit::access_atomic_cmpxchg_val_at(Node* ctl,
}
}
Node* GraphKit::access_atomic_cmpxchg_bool_at(Node* ctl,
Node* obj,
Node* GraphKit::access_atomic_cmpxchg_bool_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -1643,7 +1638,6 @@ Node* GraphKit::access_atomic_cmpxchg_bool_at(Node* ctl,
const Type* value_type,
BasicType bt,
DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS,
bt, obj, addr, alias_idx);
@ -1654,8 +1648,7 @@ Node* GraphKit::access_atomic_cmpxchg_bool_at(Node* ctl,
}
}
Node* GraphKit::access_atomic_xchg_at(Node* ctl,
Node* obj,
Node* GraphKit::access_atomic_xchg_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -1663,7 +1656,6 @@ Node* GraphKit::access_atomic_xchg_at(Node* ctl,
const Type* value_type,
BasicType bt,
DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS,
bt, obj, addr, alias_idx);
@ -1674,8 +1666,7 @@ Node* GraphKit::access_atomic_xchg_at(Node* ctl,
}
}
Node* GraphKit::access_atomic_add_at(Node* ctl,
Node* obj,
Node* GraphKit::access_atomic_add_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -1683,7 +1674,6 @@ Node* GraphKit::access_atomic_add_at(Node* ctl,
const Type* value_type,
BasicType bt,
DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS, bt, obj, addr, alias_idx);
if (access.is_raw()) {
@ -1693,8 +1683,7 @@ Node* GraphKit::access_atomic_add_at(Node* ctl,
}
}
void GraphKit::access_clone(Node* ctl, Node* src, Node* dst, Node* size, bool is_array) {
set_control(ctl);
void GraphKit::access_clone(Node* src, Node* dst, Node* size, bool is_array) {
return _barrier_set->clone(this, src, dst, size, is_array);
}
@ -3849,14 +3838,14 @@ void GraphKit::final_sync(IdealKit& ideal) {
sync_kit(ideal);
}
Node* GraphKit::load_String_length(Node* ctrl, Node* str) {
Node* len = load_array_length(load_String_value(ctrl, str));
Node* coder = load_String_coder(ctrl, str);
Node* GraphKit::load_String_length(Node* str, bool set_ctrl) {
Node* len = load_array_length(load_String_value(str, set_ctrl));
Node* coder = load_String_coder(str, set_ctrl);
// Divide length by 2 if coder is UTF16
return _gvn.transform(new RShiftINode(len, coder));
}
Node* GraphKit::load_String_value(Node* ctrl, Node* str) {
Node* GraphKit::load_String_value(Node* str, bool set_ctrl) {
int value_offset = java_lang_String::value_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
@ -3866,7 +3855,7 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) {
ciTypeArrayKlass::make(T_BYTE), true, 0);
Node* p = basic_plus_adr(str, str, value_offset);
Node* load = access_load_at(str, p, value_field_type, value_type, T_OBJECT,
IN_HEAP | C2_CONTROL_DEPENDENT_LOAD);
IN_HEAP | (set_ctrl ? C2_CONTROL_DEPENDENT_LOAD : 0) | MO_UNORDERED);
// String.value field is known to be @Stable.
if (UseImplicitStableValues) {
load = cast_array_to_stable(load, value_type);
@ -3874,7 +3863,7 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) {
return load;
}
Node* GraphKit::load_String_coder(Node* ctrl, Node* str) {
Node* GraphKit::load_String_coder(Node* str, bool set_ctrl) {
if (!CompactStrings) {
return intcon(java_lang_String::CODER_UTF16);
}
@ -3883,27 +3872,31 @@ Node* GraphKit::load_String_coder(Node* ctrl, Node* str) {
false, NULL, 0);
const TypePtr* coder_field_type = string_type->add_offset(coder_offset);
int coder_field_idx = C->get_alias_index(coder_field_type);
return make_load(ctrl, basic_plus_adr(str, str, coder_offset),
TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered);
Node* p = basic_plus_adr(str, str, coder_offset);
Node* load = access_load_at(str, p, coder_field_type, TypeInt::BYTE, T_BYTE,
IN_HEAP | (set_ctrl ? C2_CONTROL_DEPENDENT_LOAD : 0) | MO_UNORDERED);
return load;
}
void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) {
void GraphKit::store_String_value(Node* str, Node* value) {
int value_offset = java_lang_String::value_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* value_field_type = string_type->add_offset(value_offset);
access_store_at(ctrl, str, basic_plus_adr(str, value_offset), value_field_type,
value, TypeAryPtr::BYTES, T_OBJECT, IN_HEAP);
access_store_at(str, basic_plus_adr(str, value_offset), value_field_type,
value, TypeAryPtr::BYTES, T_OBJECT, IN_HEAP | MO_UNORDERED);
}
void GraphKit::store_String_coder(Node* ctrl, Node* str, Node* value) {
void GraphKit::store_String_coder(Node* str, Node* value) {
int coder_offset = java_lang_String::coder_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* coder_field_type = string_type->add_offset(coder_offset);
int coder_field_idx = C->get_alias_index(coder_field_type);
store_to_memory(ctrl, basic_plus_adr(str, coder_offset),
value, T_BYTE, coder_field_idx, MemNode::unordered);
access_store_at(str, basic_plus_adr(str, coder_offset), coder_field_type,
value, TypeInt::BYTE, T_BYTE, IN_HEAP | MO_UNORDERED);
}
// Capture src and dst memory state with a MergeMemNode

View File

@ -572,8 +572,7 @@ class GraphKit : public Phase {
// Perform decorated accesses
Node* access_store_at(Node* ctl,
Node* obj, // containing obj
Node* access_store_at(Node* obj, // containing obj
Node* adr, // actual adress to store val at
const TypePtr* adr_type,
Node* val,
@ -593,8 +592,7 @@ class GraphKit : public Phase {
BasicType bt,
DecoratorSet decorators);
Node* access_atomic_cmpxchg_val_at(Node* ctl,
Node* obj,
Node* access_atomic_cmpxchg_val_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -604,8 +602,7 @@ class GraphKit : public Phase {
BasicType bt,
DecoratorSet decorators);
Node* access_atomic_cmpxchg_bool_at(Node* ctl,
Node* obj,
Node* access_atomic_cmpxchg_bool_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -615,8 +612,7 @@ class GraphKit : public Phase {
BasicType bt,
DecoratorSet decorators);
Node* access_atomic_xchg_at(Node* ctl,
Node* obj,
Node* access_atomic_xchg_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -625,8 +621,7 @@ class GraphKit : public Phase {
BasicType bt,
DecoratorSet decorators);
Node* access_atomic_add_at(Node* ctl,
Node* obj,
Node* access_atomic_add_at(Node* obj,
Node* adr,
const TypePtr* adr_type,
int alias_idx,
@ -635,7 +630,7 @@ class GraphKit : public Phase {
BasicType bt,
DecoratorSet decorators);
void access_clone(Node* ctl, Node* src, Node* dst, Node* size, bool is_array);
void access_clone(Node* src, Node* dst, Node* size, bool is_array);
Node* access_resolve(Node* n, DecoratorSet decorators);
@ -849,11 +844,11 @@ class GraphKit : public Phase {
bool deoptimize_on_exception = false);
// java.lang.String helpers
Node* load_String_length(Node* ctrl, Node* str);
Node* load_String_value(Node* ctrl, Node* str);
Node* load_String_coder(Node* ctrl, Node* str);
void store_String_value(Node* ctrl, Node* str, Node* value);
void store_String_coder(Node* ctrl, Node* str, Node* value);
Node* load_String_length(Node* str, bool set_ctrl);
Node* load_String_value(Node* str, bool set_ctrl);
Node* load_String_coder(Node* str, bool set_ctrl);
void store_String_value(Node* str, Node* value);
void store_String_coder(Node* str, Node* value);
Node* capture_memory(const TypePtr* src_type, const TypePtr* dst_type);
Node* compress_string(Node* src, const TypeAryPtr* src_type, Node* dst, Node* count);
void inflate_string(Node* src, Node* dst, const TypeAryPtr* dst_type, Node* count);

View File

@ -543,10 +543,7 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_notify:
case vmIntrinsics::_notifyAll:
if (ObjectMonitor::Knob_InlineNotify) {
return inline_notify(intrinsic_id());
}
return false;
return inline_notify(intrinsic_id());
case vmIntrinsics::_addExactI: return inline_math_addExactI(false /* add */);
case vmIntrinsics::_addExactL: return inline_math_addExactL(false /* add */);
@ -1761,11 +1758,9 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) {
return false;
}
if (is_store) {
(void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered,
false, false, true /* mismatched */);
access_store_at(value, adr, TypeAryPtr::BYTES, ch, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED);
} else {
ch = make_load(control(), adr, TypeInt::CHAR, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered,
LoadNode::DependsOnlyOnTest, false, false, true /* mismatched */);
ch = access_load_at(value, adr, TypeAryPtr::BYTES, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD);
set_result(ch);
}
return true;
@ -2515,7 +2510,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
val = ConvL2X(val);
val = gvn().transform(new CastX2PNode(val));
}
access_store_at(control(), heap_base_oop, adr, adr_type, val, value_type, type, decorators);
access_store_at(heap_base_oop, adr, adr_type, val, value_type, type, decorators);
}
return true;
@ -2734,24 +2729,24 @@ bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadSt
Node* result = NULL;
switch (kind) {
case LS_cmp_exchange: {
result = access_atomic_cmpxchg_val_at(control(), base, adr, adr_type, alias_idx,
result = access_atomic_cmpxchg_val_at(base, adr, adr_type, alias_idx,
oldval, newval, value_type, type, decorators);
break;
}
case LS_cmp_swap_weak:
decorators |= C2_WEAK_CMPXCHG;
case LS_cmp_swap: {
result = access_atomic_cmpxchg_bool_at(control(), base, adr, adr_type, alias_idx,
result = access_atomic_cmpxchg_bool_at(base, adr, adr_type, alias_idx,
oldval, newval, value_type, type, decorators);
break;
}
case LS_get_set: {
result = access_atomic_xchg_at(control(), base, adr, adr_type, alias_idx,
result = access_atomic_xchg_at(base, adr, adr_type, alias_idx,
newval, value_type, type, decorators);
break;
}
case LS_get_add: {
result = access_atomic_add_at(control(), base, adr, adr_type, alias_idx,
result = access_atomic_add_at(base, adr, adr_type, alias_idx,
newval, value_type, type, decorators);
break;
}
@ -4235,7 +4230,7 @@ void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, b
// TODO: generate fields copies for small objects instead.
Node* size = _gvn.transform(obj_size);
access_clone(control(), obj, alloc_obj, size, is_array);
access_clone(obj, alloc_obj, size, is_array);
// Do not let reads from the cloned object float above the arraycopy.
if (alloc != NULL) {

View File

@ -104,7 +104,7 @@ void Parse::array_store(BasicType bt) {
const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt);
access_store_at(control(), array, adr, adr_type, val, elemtype, bt, MO_UNORDERED | IN_HEAP | IS_ARRAY);
access_store_at(array, adr, adr_type, val, elemtype, bt, MO_UNORDERED | IN_HEAP | IS_ARRAY);
}

View File

@ -264,7 +264,7 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
field_type = Type::BOTTOM;
}
}
access_store_at(control(), obj, adr, adr_type, val, field_type, bt, decorators);
access_store_at(obj, adr, adr_type, val, field_type, bt, decorators);
if (is_field) {
// Remember we wrote a volatile field.
@ -351,7 +351,7 @@ Node* Parse::expand_multianewarray(ciArrayKlass* array_klass, Node* *lengths, in
Node* elem = expand_multianewarray(array_klass_1, &lengths[1], ndimensions-1, nargs);
intptr_t offset = header + ((intptr_t)i << LogBytesPerHeapOop);
Node* eaddr = basic_plus_adr(array, offset);
access_store_at(control(), array, eaddr, adr_type, elem, elemtype, T_OBJECT, IN_HEAP | IS_ARRAY);
access_store_at(array, eaddr, adr_type, elem, elemtype, T_OBJECT, IN_HEAP | IS_ARRAY);
}
}
return array;

View File

@ -437,9 +437,9 @@ void Parse::set_md_flag_at(ciMethodData* md, ciProfileData* data, int flag_const
Node* adr_node = method_data_addressing(md, data, DataLayout::flags_offset());
const TypePtr* adr_type = _gvn.type(adr_node)->is_ptr();
Node* flags = make_load(NULL, adr_node, TypeInt::BYTE, T_BYTE, adr_type, MemNode::unordered);
Node* flags = make_load(NULL, adr_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered);
Node* incr = _gvn.transform(new OrINode(flags, _gvn.intcon(flag_constant)));
store_to_memory(NULL, adr_node, incr, T_BYTE, adr_type, MemNode::unordered);
store_to_memory(NULL, adr_node, incr, T_INT, adr_type, MemNode::unordered);
}
//----------------------------profile_taken_branch-----------------------------

View File

@ -1547,7 +1547,7 @@ void PhaseStringOpts::copy_constant_string(GraphKit& kit, IdealKit& ideal, ciTyp
// Compress copy contents of the byte/char String str into dst_array starting at index start.
Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* dst_array, Node* dst_coder, Node* start) {
Node* src_array = kit.load_String_value(kit.control(), str);
Node* src_array = kit.load_String_value(str, true);
src_array = kit.access_resolve(src_array, ACCESS_READ);
IdealKit ideal(&kit, true, true);
@ -1580,7 +1580,7 @@ Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* dst_array, No
// Non-constant source string
if (CompactStrings) {
// Emit runtime check for coder
Node* coder = kit.load_String_coder(__ ctrl(), str);
Node* coder = kit.load_String_coder(str, true);
__ if_then(coder, BoolTest::eq, __ ConI(java_lang_String::CODER_LATIN1)); {
// Source is Latin1
copy_latin1_string(kit, ideal, src_array, count, dst_array, dst_coder, start);
@ -1796,8 +1796,8 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
// replace the argument with the null checked version
arg = null_string;
sc->set_argument(argi, arg);
count = kit.load_String_length(kit.control(), arg);
arg_coder = kit.load_String_coder(kit.control(), arg);
count = kit.load_String_length(arg, true);
arg_coder = kit.load_String_coder(arg, true);
} else if (!type->higher_equal(TypeInstPtr::NOTNULL)) {
// s = s != null ? s : "null";
// length = length + (s.count - s.offset);
@ -1820,14 +1820,14 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
// replace the argument with the null checked version
arg = phi;
sc->set_argument(argi, arg);
count = kit.load_String_length(kit.control(), arg);
arg_coder = kit.load_String_coder(kit.control(), arg);
count = kit.load_String_length(arg, true);
arg_coder = kit.load_String_coder(arg, true);
} else {
// A corresponding nullcheck will be connected during IGVN MemNode::Ideal_common_DU_postCCP
// kit.control might be a different test, that can be hoisted above the actual nullcheck
// in case, that the control input is not null, Ideal_common_DU_postCCP will not look for a nullcheck.
count = kit.load_String_length(NULL, arg);
arg_coder = kit.load_String_coder(NULL, arg);
count = kit.load_String_length(arg, false);
arg_coder = kit.load_String_coder(arg, false);
}
if (arg->is_Con()) {
// Constant string. Get constant coder and length.
@ -1918,7 +1918,7 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
sc->mode(0) == StringConcat::StringNullCheckMode)) {
// Handle the case when there is only a single String argument.
// In this case, we can just pull the value from the String itself.
dst_array = kit.load_String_value(kit.control(), sc->argument(0));
dst_array = kit.load_String_value(sc->argument(0), true);
} else {
// Allocate destination byte array according to coder
dst_array = allocate_byte_array(kit, NULL, __ LShiftI(length, coder));
@ -1959,8 +1959,8 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
}
// Initialize the string
kit.store_String_value(kit.control(), result, dst_array);
kit.store_String_coder(kit.control(), result, coder);
kit.store_String_value(result, dst_array);
kit.store_String_coder(result, coder);
// The value field is final. Emit a barrier here to ensure that the effect
// of the initialization is committed to memory before any code publishes

View File

@ -1522,6 +1522,37 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return new BoolNode( ncmp, _test._test );
}
// Change "bool eq/ne (cmp (phi (X -X) 0))" into "bool eq/ne (cmp X 0)"
// since zero check of conditional negation of an integer is equal to
// zero check of the integer directly.
if ((_test._test == BoolTest::eq || _test._test == BoolTest::ne) &&
(cop == Op_CmpI) &&
(cmp2_type == TypeInt::ZERO) &&
(cmp1_op == Op_Phi)) {
// There should be a diamond phi with true path at index 1 or 2
PhiNode *phi = cmp1->as_Phi();
int idx_true = phi->is_diamond_phi();
if (idx_true != 0) {
// True input is in(idx_true) while false input is in(3 - idx_true)
Node *tin = phi->in(idx_true);
Node *fin = phi->in(3 - idx_true);
if ((tin->Opcode() == Op_SubI) &&
(phase->type(tin->in(1)) == TypeInt::ZERO) &&
(tin->in(2) == fin)) {
// Found conditional negation at true path, create a new CmpINode without that
Node *ncmp = phase->transform(new CmpINode(fin, cmp2));
return new BoolNode(ncmp, _test._test);
}
if ((fin->Opcode() == Op_SubI) &&
(phase->type(fin->in(1)) == TypeInt::ZERO) &&
(fin->in(2) == tin)) {
// Found conditional negation at false path, create a new CmpINode without that
Node *ncmp = phase->transform(new CmpINode(tin, cmp2));
return new BoolNode(ncmp, _test._test);
}
}
}
// Change (-A vs 0) into (A vs 0) by commuting the test. Disallow in the
// most general case because negating 0x80000000 does nothing. Needed for
// the CmpF3/SubI/CmpI idiom.

View File

@ -542,6 +542,7 @@ static SpecialFlag const special_jvm_flags[] = {
{ "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },
{ "MustCallLoadClassInternal", JDK_Version::jdk(10), JDK_Version::jdk(11), JDK_Version::jdk(12) },
{ "UnsyncloadClass", JDK_Version::jdk(10), JDK_Version::jdk(11), JDK_Version::jdk(12) },
{ "TLABStats", JDK_Version::jdk(12), JDK_Version::undefined(), JDK_Version::undefined() },
// -------------- Obsolete Flags - sorted by expired_in --------------
{ "CheckAssertionStatusDirectives",JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
@ -577,6 +578,7 @@ static SpecialFlag const special_jvm_flags[] = {
{ "EmitSync", JDK_Version::undefined(), JDK_Version::jdk(12), JDK_Version::jdk(13) },
{ "SyncVerbose", JDK_Version::undefined(), JDK_Version::jdk(12), JDK_Version::jdk(13) },
{ "SyncFlags", JDK_Version::undefined(), JDK_Version::jdk(12), JDK_Version::jdk(13) },
{ "SyncKnobs", JDK_Version::undefined(), JDK_Version::jdk(12), JDK_Version::jdk(13) },
#ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS
{ "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() },

View File

@ -827,9 +827,6 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G);
"Use LWP-based instead of libthread-based synchronization " \
"(SPARC only)") \
\
experimental(ccstr, SyncKnobs, NULL, \
"(Unstable) Various monitor synchronization tunables") \
\
product(intx, MonitorBound, 0, "Bound Monitor population") \
range(0, max_jint) \
\

View File

@ -101,39 +101,15 @@
// The knob* variables are effectively final. Once set they should
// never be modified hence. Consider using __read_mostly with GCC.
int ObjectMonitor::Knob_ExitRelease = 0;
int ObjectMonitor::Knob_InlineNotify = 1;
int ObjectMonitor::Knob_Verbose = 0;
int ObjectMonitor::Knob_VerifyInUse = 0;
int ObjectMonitor::Knob_VerifyMatch = 0;
int ObjectMonitor::Knob_SpinLimit = 5000; // derived by an external tool -
static int Knob_ReportSettings = 0;
static int Knob_SpinBase = 0; // Floor AKA SpinMin
static int Knob_SpinBackOff = 0; // spin-loop backoff
static int Knob_CASPenalty = -1; // Penalty for failed CAS
static int Knob_OXPenalty = -1; // Penalty for observed _owner change
static int Knob_SpinSetSucc = 1; // spinners set the _succ field
static int Knob_SpinEarly = 1;
static int Knob_SuccEnabled = 1; // futile wake throttling
static int Knob_SuccRestrict = 0; // Limit successors + spinners to at-most-one
static int Knob_MaxSpinners = -1; // Should be a function of # CPUs
static int Knob_Bonus = 100; // spin success bonus
static int Knob_BonusB = 100; // spin success bonus
static int Knob_Penalty = 200; // spin failure penalty
static int Knob_Poverty = 1000;
static int Knob_SpinAfterFutile = 1; // Spin after returning from park()
static int Knob_FixedSpin = 0;
static int Knob_OState = 3; // Spinner checks thread state of _owner
static int Knob_UsePause = 1;
static int Knob_ExitPolicy = 0;
static int Knob_PreSpin = 10; // 20-100 likely better
static int Knob_ResetEvent = 0;
static int BackOffMask = 0;
static int Knob_FastHSSEC = 0;
static int Knob_MoveNotifyee = 2; // notify() - disposition of notifyee
static int Knob_QMode = 0; // EntryList-cxq policy - queue discipline
static volatile int InitDone = 0;
// -----------------------------------------------------------------------------
@ -299,7 +275,7 @@ void ObjectMonitor::enter(TRAPS) {
// transitions. The following spin is strictly optional ...
// Note that if we acquire the monitor from an initial spin
// we forgo posting JVMTI events and firing DTRACE probes.
if (Knob_SpinEarly && TrySpin (Self) > 0) {
if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant");
assert(_recursions == 0, "invariant");
assert(((oop)(object()))->mark() == markOopDesc::encode(this), "invariant");
@ -461,7 +437,7 @@ void ObjectMonitor::EnterI(TRAPS) {
// to the owner. This has subtle but beneficial affinity
// effects.
if (TrySpin (Self) > 0) {
if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant");
assert(_succ != Self, "invariant");
assert(_Responsible != Self, "invariant");
@ -583,20 +559,14 @@ void ObjectMonitor::EnterI(TRAPS) {
// We can defer clearing _succ until after the spin completes
// TrySpin() must tolerate being called with _succ == Self.
// Try yet another round of adaptive spinning.
if ((Knob_SpinAfterFutile & 1) && TrySpin(Self) > 0) break;
if (TrySpin(Self) > 0) break;
// We can find that we were unpark()ed and redesignated _succ while
// we were spinning. That's harmless. If we iterate and call park(),
// park() will consume the event and return immediately and we'll
// just spin again. This pattern can repeat, leaving _succ to simply
// spin on a CPU. Enable Knob_ResetEvent to clear pending unparks().
// Alternately, we can sample fired() here, and if set, forgo spinning
// in the next iteration.
// spin on a CPU.
if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
Self->_ParkEvent->reset();
OrderAccess::fence();
}
if (_succ == Self) _succ = NULL;
// Invariant: after clearing _succ a thread *must* retry _owner before parking.
@ -675,9 +645,7 @@ void ObjectMonitor::EnterI(TRAPS) {
// contended slow-path from EnterI(). We use ReenterI() only for
// monitor reentry in wait().
//
// In the future we should reconcile EnterI() and ReenterI(), adding
// Knob_Reset and Knob_SpinAfterFutile support and restructuring the
// loop accordingly.
// In the future we should reconcile EnterI() and ReenterI().
void ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) {
assert(Self != NULL, "invariant");
@ -929,181 +897,60 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) {
for (;;) {
assert(THREAD == _owner, "invariant");
if (Knob_ExitPolicy == 0) {
// release semantics: prior loads and stores from within the critical section
// must not float (reorder) past the following store that drops the lock.
// On SPARC that requires MEMBAR #loadstore|#storestore.
// But of course in TSO #loadstore|#storestore is not required.
// I'd like to write one of the following:
// A. OrderAccess::release() ; _owner = NULL
// B. OrderAccess::loadstore(); OrderAccess::storestore(); _owner = NULL;
// Unfortunately OrderAccess::release() and OrderAccess::loadstore() both
// store into a _dummy variable. That store is not needed, but can result
// in massive wasteful coherency traffic on classic SMP systems.
// Instead, I use release_store(), which is implemented as just a simple
// ST on x64, x86 and SPARC.
OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock
OrderAccess::storeload(); // See if we need to wake a successor
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
return;
}
// Other threads are blocked trying to acquire the lock.
// release semantics: prior loads and stores from within the critical section
// must not float (reorder) past the following store that drops the lock.
// On SPARC that requires MEMBAR #loadstore|#storestore.
// But of course in TSO #loadstore|#storestore is not required.
OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock
OrderAccess::storeload(); // See if we need to wake a successor
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
return;
}
// Other threads are blocked trying to acquire the lock.
// Normally the exiting thread is responsible for ensuring succession,
// but if other successors are ready or other entering threads are spinning
// then this thread can simply store NULL into _owner and exit without
// waking a successor. The existence of spinners or ready successors
// guarantees proper succession (liveness). Responsibility passes to the
// ready or running successors. The exiting thread delegates the duty.
// More precisely, if a successor already exists this thread is absolved
// of the responsibility of waking (unparking) one.
//
// The _succ variable is critical to reducing futile wakeup frequency.
// _succ identifies the "heir presumptive" thread that has been made
// ready (unparked) but that has not yet run. We need only one such
// successor thread to guarantee progress.
// See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
// section 3.3 "Futile Wakeup Throttling" for details.
//
// Note that spinners in Enter() also set _succ non-null.
// In the current implementation spinners opportunistically set
// _succ so that exiting threads might avoid waking a successor.
// Another less appealing alternative would be for the exiting thread
// to drop the lock and then spin briefly to see if a spinner managed
// to acquire the lock. If so, the exiting thread could exit
// immediately without waking a successor, otherwise the exiting
// thread would need to dequeue and wake a successor.
// (Note that we'd need to make the post-drop spin short, but no
// shorter than the worst-case round-trip cache-line migration time.
// The dropped lock needs to become visible to the spinner, and then
// the acquisition of the lock by the spinner must become visible to
// the exiting thread).
// Normally the exiting thread is responsible for ensuring succession,
// but if other successors are ready or other entering threads are spinning
// then this thread can simply store NULL into _owner and exit without
// waking a successor. The existence of spinners or ready successors
// guarantees proper succession (liveness). Responsibility passes to the
// ready or running successors. The exiting thread delegates the duty.
// More precisely, if a successor already exists this thread is absolved
// of the responsibility of waking (unparking) one.
//
// The _succ variable is critical to reducing futile wakeup frequency.
// _succ identifies the "heir presumptive" thread that has been made
// ready (unparked) but that has not yet run. We need only one such
// successor thread to guarantee progress.
// See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
// section 3.3 "Futile Wakeup Throttling" for details.
//
// Note that spinners in Enter() also set _succ non-null.
// In the current implementation spinners opportunistically set
// _succ so that exiting threads might avoid waking a successor.
// Another less appealing alternative would be for the exiting thread
// to drop the lock and then spin briefly to see if a spinner managed
// to acquire the lock. If so, the exiting thread could exit
// immediately without waking a successor, otherwise the exiting
// thread would need to dequeue and wake a successor.
// (Note that we'd need to make the post-drop spin short, but no
// shorter than the worst-case round-trip cache-line migration time.
// The dropped lock needs to become visible to the spinner, and then
// the acquisition of the lock by the spinner must become visible to
// the exiting thread).
// It appears that an heir-presumptive (successor) must be made ready.
// Only the current lock owner can manipulate the EntryList or
// drain _cxq, so we need to reacquire the lock. If we fail
// to reacquire the lock the responsibility for ensuring succession
// falls to the new owner.
//
if (!Atomic::replace_if_null(THREAD, &_owner)) {
return;
}
} else {
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock
OrderAccess::storeload();
// Ratify the previously observed values.
if (_cxq == NULL || _succ != NULL) {
return;
}
// inopportune interleaving -- the exiting thread (this thread)
// in the fast-exit path raced an entering thread in the slow-enter
// path.
// We have two choices:
// A. Try to reacquire the lock.
// If the CAS() fails return immediately, otherwise
// we either restart/rerun the exit operation, or simply
// fall-through into the code below which wakes a successor.
// B. If the elements forming the EntryList|cxq are TSM
// we could simply unpark() the lead thread and return
// without having set _succ.
if (!Atomic::replace_if_null(THREAD, &_owner)) {
return;
}
}
// It appears that an heir-presumptive (successor) must be made ready.
// Only the current lock owner can manipulate the EntryList or
// drain _cxq, so we need to reacquire the lock. If we fail
// to reacquire the lock the responsibility for ensuring succession
// falls to the new owner.
//
if (!Atomic::replace_if_null(THREAD, &_owner)) {
return;
}
guarantee(_owner == THREAD, "invariant");
ObjectWaiter * w = NULL;
int QMode = Knob_QMode;
if (QMode == 2 && _cxq != NULL) {
// QMode == 2 : cxq has precedence over EntryList.
// Try to directly wake a successor from the cxq.
// If successful, the successor will need to unlink itself from cxq.
w = _cxq;
assert(w != NULL, "invariant");
assert(w->TState == ObjectWaiter::TS_CXQ, "Invariant");
ExitEpilog(Self, w);
return;
}
if (QMode == 3 && _cxq != NULL) {
// Aggressively drain cxq into EntryList at the first opportunity.
// This policy ensure that recently-run threads live at the head of EntryList.
// Drain _cxq into EntryList - bulk transfer.
// First, detach _cxq.
// The following loop is tantamount to: w = swap(&cxq, NULL)
w = _cxq;
for (;;) {
assert(w != NULL, "Invariant");
ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
if (u == w) break;
w = u;
}
assert(w != NULL, "invariant");
ObjectWaiter * q = NULL;
ObjectWaiter * p;
for (p = w; p != NULL; p = p->_next) {
guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
p->TState = ObjectWaiter::TS_ENTER;
p->_prev = q;
q = p;
}
// Append the RATs to the EntryList
// TODO: organize EntryList as a CDLL so we can locate the tail in constant-time.
ObjectWaiter * Tail;
for (Tail = _EntryList; Tail != NULL && Tail->_next != NULL;
Tail = Tail->_next)
/* empty */;
if (Tail == NULL) {
_EntryList = w;
} else {
Tail->_next = w;
w->_prev = Tail;
}
// Fall thru into code that tries to wake a successor from EntryList
}
if (QMode == 4 && _cxq != NULL) {
// Aggressively drain cxq into EntryList at the first opportunity.
// This policy ensure that recently-run threads live at the head of EntryList.
// Drain _cxq into EntryList - bulk transfer.
// First, detach _cxq.
// The following loop is tantamount to: w = swap(&cxq, NULL)
w = _cxq;
for (;;) {
assert(w != NULL, "Invariant");
ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
if (u == w) break;
w = u;
}
assert(w != NULL, "invariant");
ObjectWaiter * q = NULL;
ObjectWaiter * p;
for (p = w; p != NULL; p = p->_next) {
guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
p->TState = ObjectWaiter::TS_ENTER;
p->_prev = q;
q = p;
}
// Prepend the RATs to the EntryList
if (_EntryList != NULL) {
q->_next = _EntryList;
_EntryList->_prev = q;
}
_EntryList = w;
// Fall thru into code that tries to wake a successor from EntryList
}
w = _EntryList;
if (w != NULL) {
@ -1150,34 +997,14 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) {
// TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
// we have faster access to the tail.
if (QMode == 1) {
// QMode == 1 : drain cxq to EntryList, reversing order
// We also reverse the order of the list.
ObjectWaiter * s = NULL;
ObjectWaiter * t = w;
ObjectWaiter * u = NULL;
while (t != NULL) {
guarantee(t->TState == ObjectWaiter::TS_CXQ, "invariant");
t->TState = ObjectWaiter::TS_ENTER;
u = t->_next;
t->_prev = u;
t->_next = s;
s = t;
t = u;
}
_EntryList = s;
assert(s != NULL, "invariant");
} else {
// QMode == 0 or QMode == 2
_EntryList = w;
ObjectWaiter * q = NULL;
ObjectWaiter * p;
for (p = w; p != NULL; p = p->_next) {
guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
p->TState = ObjectWaiter::TS_ENTER;
p->_prev = q;
q = p;
}
_EntryList = w;
ObjectWaiter * q = NULL;
ObjectWaiter * p;
for (p = w; p != NULL; p = p->_next) {
guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
p->TState = ObjectWaiter::TS_ENTER;
p->_prev = q;
q = p;
}
// In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
@ -1226,22 +1053,8 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) {
// ST Self->_suspend_equivalent = false
// MEMBAR
// LD Self_>_suspend_flags
//
// UPDATE 2007-10-6: since I've replaced the native Mutex/Monitor subsystem
// with a more efficient implementation, the need to use "FastHSSEC" has
// decreased. - Dave
bool ObjectMonitor::ExitSuspendEquivalent(JavaThread * jSelf) {
const int Mode = Knob_FastHSSEC;
if (Mode && !jSelf->is_external_suspend()) {
assert(jSelf->is_suspend_equivalent(), "invariant");
jSelf->clear_suspend_equivalent();
if (2 == Mode) OrderAccess::storeload();
if (!jSelf->is_external_suspend()) return false;
// We raced a suspension -- fall thru into the slow path
jSelf->set_suspend_equivalent();
}
return jSelf->handle_special_suspend_equivalent_condition();
}
@ -1255,7 +1068,7 @@ void ObjectMonitor::ExitEpilog(Thread * Self, ObjectWaiter * Wakee) {
// 2. ST _owner = NULL
// 3. unpark(wakee)
_succ = Knob_SuccEnabled ? Wakee->_thread : NULL;
_succ = Wakee->_thread;
ParkEvent * Trigger = Wakee->_event;
// Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again.
@ -1348,12 +1161,6 @@ void ObjectMonitor::check_slow(TRAPS) {
THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), "current thread not owner");
}
static int Adjust(volatile int * adr, int dx) {
int v;
for (v = *adr; Atomic::cmpxchg(v + dx, adr, v) != v; v = *adr) /* empty */;
return v;
}
static void post_monitor_wait_event(EventJavaMonitorWait* event,
ObjectMonitor* monitor,
jlong notifier_tid,
@ -1599,8 +1406,6 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
// we might just dequeue a thread from the WaitSet and directly unpark() it.
void ObjectMonitor::INotify(Thread * Self) {
const int policy = Knob_MoveNotifyee;
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify");
ObjectWaiter * iterator = DequeueWaiter();
if (iterator != NULL) {
@ -1611,9 +1416,9 @@ void ObjectMonitor::INotify(Thread * Self) {
// or head (policy == 0).
// b. push it onto the front of the _cxq (policy == 2).
// For now we use (b).
if (policy != 4) {
iterator->TState = ObjectWaiter::TS_ENTER;
}
iterator->TState = ObjectWaiter::TS_ENTER;
iterator->_notified = 1;
iterator->_notifier_tid = JFR_THREAD_ID(Self);
@ -1624,67 +1429,19 @@ void ObjectMonitor::INotify(Thread * Self) {
assert(list != iterator, "invariant");
}
if (policy == 0) { // prepend to EntryList
if (list == NULL) {
iterator->_next = iterator->_prev = NULL;
_EntryList = iterator;
} else {
list->_prev = iterator;
iterator->_next = list;
iterator->_prev = NULL;
_EntryList = iterator;
}
} else if (policy == 1) { // append to EntryList
if (list == NULL) {
iterator->_next = iterator->_prev = NULL;
_EntryList = iterator;
} else {
// CONSIDER: finding the tail currently requires a linear-time walk of
// the EntryList. We can make tail access constant-time by converting to
// a CDLL instead of using our current DLL.
ObjectWaiter * tail;
for (tail = list; tail->_next != NULL; tail = tail->_next) {}
assert(tail != NULL && tail->_next == NULL, "invariant");
tail->_next = iterator;
iterator->_prev = tail;
iterator->_next = NULL;
}
} else if (policy == 2) { // prepend to cxq
if (list == NULL) {
iterator->_next = iterator->_prev = NULL;
_EntryList = iterator;
} else {
iterator->TState = ObjectWaiter::TS_CXQ;
for (;;) {
ObjectWaiter * front = _cxq;
iterator->_next = front;
if (Atomic::cmpxchg(iterator, &_cxq, front) == front) {
break;
}
}
}
} else if (policy == 3) { // append to cxq
// prepend to cxq
if (list == NULL) {
iterator->_next = iterator->_prev = NULL;
_EntryList = iterator;
} else {
iterator->TState = ObjectWaiter::TS_CXQ;
for (;;) {
ObjectWaiter * tail = _cxq;
if (tail == NULL) {
iterator->_next = NULL;
if (Atomic::replace_if_null(iterator, &_cxq)) {
break;
}
} else {
while (tail->_next != NULL) tail = tail->_next;
tail->_next = iterator;
iterator->_prev = tail;
iterator->_next = NULL;
ObjectWaiter * front = _cxq;
iterator->_next = front;
if (Atomic::cmpxchg(iterator, &_cxq, front) == front) {
break;
}
}
} else {
ParkEvent * ev = iterator->_event;
iterator->TState = ObjectWaiter::TS_RUN;
OrderAccess::fence();
ev->unpark();
}
// _WaitSetLock protects the wait queue, not the EntryList. We could
@ -1695,9 +1452,7 @@ void ObjectMonitor::INotify(Thread * Self) {
// on _WaitSetLock so it's not profitable to reduce the length of the
// critical section.
if (policy < 4) {
iterator->wait_reenter_begin(this);
}
iterator->wait_reenter_begin(this);
}
Thread::SpinRelease(&_WaitSetLock);
}
@ -1854,33 +1609,19 @@ int ObjectMonitor::TrySpin(Thread * Self) {
// hold the duration constant but vary the frequency.
ctr = _SpinDuration;
if (ctr < Knob_SpinBase) ctr = Knob_SpinBase;
if (ctr <= 0) return 0;
if (Knob_SuccRestrict && _succ != NULL) return 0;
if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
if (NotRunnable(Self, (Thread *) _owner)) {
return 0;
}
int MaxSpin = Knob_MaxSpinners;
if (MaxSpin >= 0) {
if (_Spinner > MaxSpin) {
return 0;
}
// Slightly racy, but benign ...
Adjust(&_Spinner, 1);
}
// We're good to spin ... spin ingress.
// CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades
// when preparing to LD...CAS _owner, etc and the CAS is likely
// to succeed.
int hits = 0;
int msk = 0;
int caspty = Knob_CASPenalty;
int oxpty = Knob_OXPenalty;
int sss = Knob_SpinSetSucc;
if (sss && _succ == NULL) _succ = Self;
if (_succ == NULL) {
_succ = Self;
}
Thread * prv = NULL;
// There are three ways to exit the following loop:
@ -1903,32 +1644,7 @@ int ObjectMonitor::TrySpin(Thread * Self) {
if (SafepointMechanism::poll(Self)) {
goto Abort; // abrupt spin egress
}
if (Knob_UsePause & 1) SpinPause();
}
if (Knob_UsePause & 2) SpinPause();
// Exponential back-off ... Stay off the bus to reduce coherency traffic.
// This is useful on classic SMP systems, but is of less utility on
// N1-style CMT platforms.
//
// Trade-off: lock acquisition latency vs coherency bandwidth.
// Lock hold times are typically short. A histogram
// of successful spin attempts shows that we usually acquire
// the lock early in the spin. That suggests we want to
// sample _owner frequently in the early phase of the spin,
// but then back-off and sample less frequently as the spin
// progresses. The back-off makes a good citizen on SMP big
// SMP systems. Oversampling _owner can consume excessive
// coherency bandwidth. Relatedly, if we _oversample _owner we
// can inadvertently interfere with the the ST m->owner=null.
// executed by the lock owner.
if (ctr & msk) continue;
++hits;
if ((hits & 0xF) == 0) {
// The 0xF, above, corresponds to the exponent.
// Consider: (msk+1)|msk
msk = ((msk << 2)|3) & BackOffMask;
SpinPause();
}
// Probe _owner with TATAS
@ -1947,10 +1663,9 @@ int ObjectMonitor::TrySpin(Thread * Self) {
if (ox == NULL) {
// The CAS succeeded -- this thread acquired ownership
// Take care of some bookkeeping to exit spin state.
if (sss && _succ == Self) {
if (_succ == Self) {
_succ = NULL;
}
if (MaxSpin > 0) Adjust(&_Spinner, -1);
// Increase _SpinDuration :
// The spin was successful (profitable) so we tend toward
@ -1968,22 +1683,17 @@ int ObjectMonitor::TrySpin(Thread * Self) {
}
// The CAS failed ... we can take any of the following actions:
// * penalize: ctr -= Knob_CASPenalty
// * penalize: ctr -= CASPenalty
// * exit spin with prejudice -- goto Abort;
// * exit spin without prejudice.
// * Since CAS is high-latency, retry again immediately.
prv = ox;
if (caspty == -2) break;
if (caspty == -1) goto Abort;
ctr -= caspty;
continue;
goto Abort;
}
// Did lock ownership change hands ?
if (ox != prv && prv != NULL) {
if (oxpty == -2) break;
if (oxpty == -1) goto Abort;
ctr -= oxpty;
goto Abort;
}
prv = ox;
@ -1991,10 +1701,12 @@ int ObjectMonitor::TrySpin(Thread * Self) {
// The owner must be executing in order to drop the lock.
// Spinning while the owner is OFFPROC is idiocy.
// Consider: ctr -= RunnablePenalty ;
if (Knob_OState && NotRunnable (Self, ox)) {
if (NotRunnable(Self, ox)) {
goto Abort;
}
if (sss && _succ == NULL) _succ = Self;
if (_succ == NULL) {
_succ = Self;
}
}
// Spin failed with prejudice -- reduce _SpinDuration.
@ -2012,8 +1724,7 @@ int ObjectMonitor::TrySpin(Thread * Self) {
}
Abort:
if (MaxSpin >= 0) Adjust(&_Spinner, -1);
if (sss && _succ == Self) {
if (_succ == Self) {
_succ = NULL;
// Invariant: after setting succ=null a contending thread
// must recheck-retry _owner before parking. This usually happens
@ -2204,29 +1915,6 @@ void ObjectMonitor::Initialize() {
}
}
static char * kvGet(char * kvList, const char * Key) {
if (kvList == NULL) return NULL;
size_t n = strlen(Key);
char * Search;
for (Search = kvList; *Search; Search += strlen(Search) + 1) {
if (strncmp (Search, Key, n) == 0) {
if (Search[n] == '=') return Search + n + 1;
if (Search[n] == 0) return(char *) "1";
}
}
return NULL;
}
static int kvGetInt(char * kvList, const char * Key, int Default) {
char * v = kvGet(kvList, Key);
int rslt = v ? ::strtol(v, NULL, 0) : Default;
if (Knob_ReportSettings && v != NULL) {
tty->print_cr("INFO: SyncKnob: %s %d(%d)", Key, rslt, Default) ;
tty->flush();
}
return rslt;
}
void ObjectMonitor::DeferredInitialize() {
if (InitDone > 0) return;
if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) {
@ -2237,70 +1925,13 @@ void ObjectMonitor::DeferredInitialize() {
// One-shot global initialization ...
// The initialization is idempotent, so we don't need locks.
// In the future consider doing this via os::init_2().
// SyncKnobs consist of <Key>=<Value> pairs in the style
// of environment variables. Start by converting ':' to NUL.
if (SyncKnobs == NULL) SyncKnobs = "";
size_t sz = strlen(SyncKnobs);
char * knobs = (char *) os::malloc(sz + 2, mtInternal);
if (knobs == NULL) {
vm_exit_out_of_memory(sz + 2, OOM_MALLOC_ERROR, "Parse SyncKnobs");
guarantee(0, "invariant");
}
strcpy(knobs, SyncKnobs);
knobs[sz+1] = 0;
for (char * p = knobs; *p; p++) {
if (*p == ':') *p = 0;
}
#define SETKNOB(x) { Knob_##x = kvGetInt(knobs, #x, Knob_##x); }
SETKNOB(ReportSettings);
SETKNOB(ExitRelease);
SETKNOB(InlineNotify);
SETKNOB(Verbose);
SETKNOB(VerifyInUse);
SETKNOB(VerifyMatch);
SETKNOB(FixedSpin);
SETKNOB(SpinLimit);
SETKNOB(SpinBase);
SETKNOB(SpinBackOff);
SETKNOB(CASPenalty);
SETKNOB(OXPenalty);
SETKNOB(SpinSetSucc);
SETKNOB(SuccEnabled);
SETKNOB(SuccRestrict);
SETKNOB(Penalty);
SETKNOB(Bonus);
SETKNOB(BonusB);
SETKNOB(Poverty);
SETKNOB(SpinAfterFutile);
SETKNOB(UsePause);
SETKNOB(SpinEarly);
SETKNOB(OState);
SETKNOB(MaxSpinners);
SETKNOB(PreSpin);
SETKNOB(ExitPolicy);
SETKNOB(QMode);
SETKNOB(ResetEvent);
SETKNOB(MoveNotifyee);
SETKNOB(FastHSSEC);
#undef SETKNOB
if (os::is_MP()) {
BackOffMask = (1 << Knob_SpinBackOff) - 1;
if (Knob_ReportSettings) {
tty->print_cr("INFO: BackOffMask=0x%X", BackOffMask);
}
// CONSIDER: BackOffMask = ROUNDUP_NEXT_POWER2 (ncpus-1)
} else {
if (!os::is_MP()) {
Knob_SpinLimit = 0;
Knob_SpinBase = 0;
Knob_PreSpin = 0;
Knob_FixedSpin = -1;
}
os::free(knobs);
OrderAccess::fence();
InitDone = 1;
}

View File

@ -195,11 +195,6 @@ class ObjectMonitor {
static PerfCounter * _sync_Deflations;
static PerfLongVariable * _sync_MonExtant;
static int Knob_ExitRelease;
static int Knob_InlineNotify;
static int Knob_Verbose;
static int Knob_VerifyInUse;
static int Knob_VerifyMatch;
static int Knob_SpinLimit;
void* operator new (size_t size) throw();

View File

@ -598,7 +598,8 @@ private:
public:
ParallelSPCleanupThreadClosure(DeflateMonitorCounters* counters) :
_nmethod_cl(NMethodSweeper::prepare_mark_active_nmethods()), _counters(counters) {}
_nmethod_cl(UseCodeAging ? NMethodSweeper::prepare_reset_hotness_counters() : NULL),
_counters(counters) {}
void do_thread(Thread* thread) {
ObjectSynchronizer::deflate_thread_local_monitors(thread, _counters);

View File

@ -28,15 +28,19 @@
#include "code/icBuffer.hpp"
#include "code/nmethod.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/workgroup.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/method.hpp"
#include "runtime/atomic.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/handshake.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/os.hpp"
@ -197,6 +201,38 @@ bool NMethodSweeper::wait_for_stack_scanning() {
return _current.end();
}
class NMethodMarkingThreadClosure : public ThreadClosure {
private:
CodeBlobClosure* _cl;
public:
NMethodMarkingThreadClosure(CodeBlobClosure* cl) : _cl(cl) {}
void do_thread(Thread* thread) {
if (thread->is_Java_thread() && ! thread->is_Code_cache_sweeper_thread()) {
JavaThread* jt = (JavaThread*) thread;
jt->nmethods_do(_cl);
}
}
};
class NMethodMarkingTask : public AbstractGangTask {
private:
NMethodMarkingThreadClosure* _cl;
public:
NMethodMarkingTask(NMethodMarkingThreadClosure* cl) :
AbstractGangTask("Parallel NMethod Marking"),
_cl(cl) {
Threads::change_thread_claim_parity();
}
~NMethodMarkingTask() {
Threads::assert_all_threads_claimed();
}
void work(uint worker_id) {
Threads::possibly_parallel_threads_do(true, _cl);
}
};
/**
* Scans the stacks of all Java threads and marks activations of not-entrant methods.
* No need to synchronize access, since 'mark_active_nmethods' is always executed at a
@ -205,12 +241,56 @@ bool NMethodSweeper::wait_for_stack_scanning() {
void NMethodSweeper::mark_active_nmethods() {
CodeBlobClosure* cl = prepare_mark_active_nmethods();
if (cl != NULL) {
Threads::nmethods_do(cl);
WorkGang* workers = Universe::heap()->get_safepoint_workers();
if (workers != NULL) {
NMethodMarkingThreadClosure tcl(cl);
NMethodMarkingTask task(&tcl);
workers->run_task(&task);
} else {
Threads::nmethods_do(cl);
}
}
}
CodeBlobClosure* NMethodSweeper::prepare_mark_active_nmethods() {
#ifdef ASSERT
if (ThreadLocalHandshakes) {
assert(Thread::current()->is_Code_cache_sweeper_thread(), "must be executed under CodeCache_lock and in sweeper thread");
assert_lock_strong(CodeCache_lock);
} else {
assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
}
#endif
// If we do not want to reclaim not-entrant or zombie methods there is no need
// to scan stacks
if (!MethodFlushing) {
return NULL;
}
// Increase time so that we can estimate when to invoke the sweeper again.
_time_counter++;
// Check for restart
assert(_current.method() == NULL, "should only happen between sweeper cycles");
assert(wait_for_stack_scanning(), "should only happen between sweeper cycles");
_seen = 0;
_current = CompiledMethodIterator();
// Initialize to first nmethod
_current.next();
_traversals += 1;
_total_time_this_sweep = Tickspan();
if (PrintMethodFlushing) {
tty->print_cr("### Sweep: stack traversal %ld", _traversals);
}
return &mark_activation_closure;
}
CodeBlobClosure* NMethodSweeper::prepare_reset_hotness_counters() {
assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
// If we do not want to reclaim not-entrant or zombie methods there is no need
// to scan stacks
if (!MethodFlushing) {
@ -231,24 +311,7 @@ CodeBlobClosure* NMethodSweeper::prepare_mark_active_nmethods() {
}
}
if (wait_for_stack_scanning()) {
_seen = 0;
_current = CompiledMethodIterator();
// Initialize to first nmethod
_current.next();
_traversals += 1;
_total_time_this_sweep = Tickspan();
if (PrintMethodFlushing) {
tty->print_cr("### Sweep: stack traversal %ld", _traversals);
}
return &mark_activation_closure;
} else {
// Only set hotness counter
return &set_hotness_closure;
}
return &set_hotness_closure;
}
/**
@ -258,8 +321,20 @@ CodeBlobClosure* NMethodSweeper::prepare_mark_active_nmethods() {
void NMethodSweeper::do_stack_scanning() {
assert(!CodeCache_lock->owned_by_self(), "just checking");
if (wait_for_stack_scanning()) {
VM_MarkActiveNMethods op;
VMThread::execute(&op);
if (ThreadLocalHandshakes) {
CodeBlobClosure* code_cl;
{
MutexLockerEx ccl(CodeCache_lock, Mutex::_no_safepoint_check_flag);
code_cl = prepare_mark_active_nmethods();
}
if (code_cl != NULL) {
NMethodMarkingThreadClosure tcl(code_cl);
Handshake::execute(&tcl);
}
} else {
VM_MarkActiveNMethods op;
VMThread::execute(&op);
}
_should_sweep = true;
}
}

View File

@ -117,6 +117,7 @@ class NMethodSweeper : public AllStatic {
static void mark_active_nmethods(); // Invoked at the end of each safepoint
static CodeBlobClosure* prepare_mark_active_nmethods();
static CodeBlobClosure* prepare_reset_hotness_counters();
static void sweeper_loop();
static void notify(int code_blob_type); // Possibly start the sweeper thread.
static void force_sweep();

View File

@ -1050,40 +1050,14 @@ static void InduceScavenge(Thread * Self, const char * Whence) {
// TODO: assert thread state is reasonable
if (ForceMonitorScavenge == 0 && Atomic::xchg (1, &ForceMonitorScavenge) == 0) {
if (ObjectMonitor::Knob_Verbose) {
tty->print_cr("INFO: Monitor scavenge - Induced STW @%s (%d)",
Whence, ForceMonitorScavenge) ;
tty->flush();
}
// Induce a 'null' safepoint to scavenge monitors
// Must VM_Operation instance be heap allocated as the op will be enqueue and posted
// to the VMthread and have a lifespan longer than that of this activation record.
// The VMThread will delete the op when completed.
VMThread::execute(new VM_ScavengeMonitors());
if (ObjectMonitor::Knob_Verbose) {
tty->print_cr("INFO: Monitor scavenge - STW posted @%s (%d)",
Whence, ForceMonitorScavenge) ;
tty->flush();
}
}
}
void ObjectSynchronizer::verifyInUse(Thread *Self) {
ObjectMonitor* mid;
int in_use_tally = 0;
for (mid = Self->omInUseList; mid != NULL; mid = mid->FreeNext) {
in_use_tally++;
}
assert(in_use_tally == Self->omInUseCount, "in-use count off");
int free_tally = 0;
for (mid = Self->omFreeList; mid != NULL; mid = mid->FreeNext) {
free_tally++;
}
assert(free_tally == Self->omFreeCount, "free count off");
}
ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
// A large MAXPRIVATE value reduces both list lock contention
// and list coherency traffic, but also tends to increase the
@ -1110,9 +1084,6 @@ ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
m->FreeNext = Self->omInUseList;
Self->omInUseList = m;
Self->omInUseCount++;
if (ObjectMonitor::Knob_VerifyInUse) {
verifyInUse(Self);
}
} else {
m->FreeNext = NULL;
}
@ -1250,9 +1221,6 @@ void ObjectSynchronizer::omRelease(Thread * Self, ObjectMonitor * m,
}
extracted = true;
Self->omInUseCount--;
if (ObjectMonitor::Knob_VerifyInUse) {
verifyInUse(Self);
}
break;
}
}
@ -1763,14 +1731,6 @@ void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* co
// Consider: audit gFreeList to ensure that gMonitorFreeCount and list agree.
if (ObjectMonitor::Knob_Verbose) {
tty->print_cr("INFO: Deflate: InCirc=%d InUse=%d Scavenged=%d "
"ForceMonitorScavenge=%d : pop=%d free=%d",
counters->nInCirculation, counters->nInuse, counters->nScavenged, ForceMonitorScavenge,
gMonitorPopulation, gMonitorFreeCount);
tty->flush();
}
ForceMonitorScavenge = 0; // Reset
OM_PERFDATA_OP(Deflations, inc(counters->nScavenged));
@ -1796,9 +1756,6 @@ void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMo
// Adjust counters
counters->nInCirculation += thread->omInUseCount;
thread->omInUseCount -= deflated_count;
if (ObjectMonitor::Knob_VerifyInUse) {
verifyInUse(thread);
}
counters->nScavenged += deflated_count;
counters->nInuse += thread->omInUseCount;
@ -1827,15 +1784,6 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure {
ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {}
void do_monitor(ObjectMonitor* mid) {
if (mid->owner() == THREAD) {
if (ObjectMonitor::Knob_VerifyMatch != 0) {
ResourceMark rm;
Handle obj(THREAD, (oop) mid->object());
tty->print("INFO: unexpected locked object:");
javaVFrame::print_locked_object_class_name(tty, obj, "locked");
fatal("exiting JavaThread=" INTPTR_FORMAT
" unexpectedly owns ObjectMonitor=" INTPTR_FORMAT,
p2i(THREAD), p2i(mid));
}
(void)mid->complete_exit(CHECK);
}
}

View File

@ -105,7 +105,6 @@ class ObjectSynchronizer : AllStatic {
static void reenter (Handle obj, intptr_t recursion, TRAPS);
// thread-specific and global objectMonitor free list accessors
static void verifyInUse(Thread * Self);
static ObjectMonitor * omAlloc(Thread * Self);
static void omRelease(Thread * Self, ObjectMonitor * m,
bool FromPerThreadAlloc);

View File

@ -1953,13 +1953,9 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
// between JNI-acquired and regular Java monitors. We can only see
// regular Java monitors here if monitor enter-exit matching is broken.
//
// Optionally release any monitors for regular JavaThread exits. This
// is provided as a work around for any bugs in monitor enter-exit
// matching. This can be expensive so it is not enabled by default.
//
// ensure_join() ignores IllegalThreadStateExceptions, and so does
// ObjectSynchronizer::release_monitors_owned_by_thread().
if (exit_type == jni_detach || ObjectMonitor::Knob_ExitRelease) {
if (exit_type == jni_detach) {
// Sanity check even though JNI DetachCurrentThread() would have
// returned JNI_ERR if there was a Java frame. JavaThread exit
// should be done executing Java code by the time we get here.

View File

@ -255,11 +255,6 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
}
}
print_locked_object_class_name(st, Handle(THREAD, monitor->owner()), lock_state);
if (ObjectMonitor::Knob_Verbose && mark != NULL) {
st->print("\t- lockbits=");
mark->print_on(st);
st->cr();
}
found_first_monitor = true;
}

View File

@ -220,6 +220,8 @@ const char* Abstract_VM_Version::internal_vm_info_string() {
#define HOTSPOT_BUILD_COMPILER "MS VC++ 14.0 (VS2015)"
#elif _MSC_VER == 1912
#define HOTSPOT_BUILD_COMPILER "MS VC++ 15.5 (VS2017)"
#elif _MSC_VER == 1913
#define HOTSPOT_BUILD_COMPILER "MS VC++ 15.6 (VS2017)"
#else
#define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER)
#endif

View File

@ -802,7 +802,13 @@ public final class DateTimeFormatterBuilder {
return store.getText(value, style);
}
@Override
public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
public Iterator<Entry<String, Long>> getTextIterator(Chronology chrono,
TemporalField field, TextStyle style, Locale locale) {
return store.getTextIterator(style);
}
@Override
public Iterator<Entry<String, Long>> getTextIterator(TemporalField field,
TextStyle style, Locale locale) {
return store.getTextIterator(style);
}
};

View File

@ -28,6 +28,7 @@ package java.util;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.util.ArraysSupport;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.concurrent.ForkJoinPool;
import java.util.function.BinaryOperator;
@ -4288,21 +4289,41 @@ public class Arrays {
// Misc
/**
* Returns a fixed-size list backed by the specified array. (Changes to
* the returned list "write through" to the array.) This method acts
* as bridge between array-based and collection-based APIs, in
* combination with {@link Collection#toArray}. The returned list is
* serializable and implements {@link RandomAccess}.
* Returns a fixed-size list backed by the specified array. Changes made to
* the array will be visible in the returned list, and changes made to the
* list will be visible in the array. The returned list is
* {@link Serializable} and implements {@link RandomAccess}.
*
* <p>The returned list implements the optional {@code Collection} methods, except
* those that would change the size of the returned list. Those methods leave
* the list unchanged and throw {@link UnsupportedOperationException}.
*
* @apiNote
* This method acts as bridge between array-based and collection-based
* APIs, in combination with {@link Collection#toArray}.
*
* <p>This method provides a way to wrap an existing array:
* <pre>{@code
* Integer[] numbers = ...
* ...
* List<Integer> values = Arrays.asList(numbers);
* }</pre>
*
* <p>This method also provides a convenient way to create a fixed-size
* list initialized to contain several elements:
* <pre>
* List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
* </pre>
* <pre>{@code
* List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
* }</pre>
*
* <p><em>The list returned by this method is modifiable.</em>
* To create an unmodifiable list, use
* {@link Collections#unmodifiableList Collections.unmodifiableList}
* or <a href="List.html#unmodifiable">Unmodifiable Lists</a>.
*
* @param <T> the class of the objects in the array
* @param a the array by which the list will be backed
* @return a list view of the specified array
* @throws NullPointerException if the specified array is {@code null}
*/
@SafeVarargs
@SuppressWarnings("varargs")

View File

@ -369,8 +369,12 @@ public class Attributes implements Map<Object,Object>, Cloneable {
* Reads attributes from the specified input stream.
* XXX Need to handle UTF8 values.
*/
@SuppressWarnings("deprecation")
void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException {
read(is, lbuf, null, 0);
}
@SuppressWarnings("deprecation")
int read(Manifest.FastInputStream is, byte[] lbuf, String filename, int lineNumber) throws IOException {
String name = null, value;
byte[] lastline = null;
@ -378,8 +382,11 @@ public class Attributes implements Map<Object,Object>, Cloneable {
while ((len = is.readLine(lbuf)) != -1) {
boolean lineContinued = false;
byte c = lbuf[--len];
lineNumber++;
if (c != '\n' && c != '\r') {
throw new IOException("line too long");
throw new IOException("line too long ("
+ Manifest.getErrorPosition(filename, lineNumber) + ")");
}
if (len > 0 && lbuf[len-1] == '\r') {
--len;
@ -391,7 +398,8 @@ public class Attributes implements Map<Object,Object>, Cloneable {
if (lbuf[0] == ' ') {
// continuation of previous line
if (name == null) {
throw new IOException("misplaced continuation line");
throw new IOException("misplaced continuation line ("
+ Manifest.getErrorPosition(filename, lineNumber) + ")");
}
lineContinued = true;
byte[] buf = new byte[lastline.length + len - 1];
@ -406,11 +414,13 @@ public class Attributes implements Map<Object,Object>, Cloneable {
} else {
while (lbuf[i++] != ':') {
if (i >= len) {
throw new IOException("invalid header field");
throw new IOException("invalid header field ("
+ Manifest.getErrorPosition(filename, lineNumber) + ")");
}
}
if (lbuf[i++] != ' ') {
throw new IOException("invalid header field");
throw new IOException("invalid header field ("
+ Manifest.getErrorPosition(filename, lineNumber) + ")");
}
name = new String(lbuf, 0, 0, i - 2);
if (is.peek() == ' ') {
@ -433,9 +443,11 @@ public class Attributes implements Map<Object,Object>, Cloneable {
+ "entry in the jar file.");
}
} catch (IllegalArgumentException e) {
throw new IOException("invalid header field name: " + name);
throw new IOException("invalid header field name: " + name
+ " (" + Manifest.getErrorPosition(filename, lineNumber) + ")");
}
}
return lineNumber;
}
/**

View File

@ -417,12 +417,12 @@ class JarFile extends ZipFile {
if (manEntry != null) {
if (verify) {
byte[] b = getBytes(manEntry);
man = new Manifest(new ByteArrayInputStream(b));
man = new Manifest(new ByteArrayInputStream(b), getName());
if (!jvInitialized) {
jv = new JarVerifier(b);
}
} else {
man = new Manifest(super.getInputStream(manEntry));
man = new Manifest(super.getInputStream(manEntry), getName());
}
manRef = new SoftReference<>(man);
}

View File

@ -25,14 +25,15 @@
package java.util.jar;
import java.io.FilterInputStream;
import java.io.DataOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import sun.security.util.SecurityProperties;
/**
* The Manifest class is used to maintain Manifest entry names and their
@ -47,16 +48,24 @@ import java.util.Iterator;
* @since 1.2
*/
public class Manifest implements Cloneable {
private static final boolean jarInfoInExceptionText =
SecurityProperties.includedInExceptions("jar");
// manifest main attributes
private Attributes attr = new Attributes();
// manifest entries
private Map<String, Attributes> entries = new HashMap<>();
// name of the corresponding jar archive if available.
private final String jarFilename;
/**
* Constructs a new, empty Manifest.
*/
public Manifest() {
jarFilename = null;
}
/**
@ -66,15 +75,29 @@ public class Manifest implements Cloneable {
* @throws IOException if an I/O error has occurred
*/
public Manifest(InputStream is) throws IOException {
this();
read(is);
}
/**
* Constructs a new Manifest from the specified input stream.
*
* @param is the input stream containing manifest data
* @param jarFilename the name of the corresponding jar archive if available
* @throws IOException if an I/O error has occured
*/
Manifest(InputStream is, String jarFilename) throws IOException {
read(is);
this.jarFilename = jarFilename;
}
/**
* Constructs a new Manifest that is a copy of the specified Manifest.
*
* @param man the Manifest to copy
*/
public Manifest(Manifest man) {
this();
attr.putAll(man.getMainAttributes());
entries.putAll(man.getEntries());
}
@ -179,6 +202,14 @@ public class Manifest implements Cloneable {
return;
}
static String getErrorPosition(String filename, final int lineNumber) {
if (filename == null || !jarInfoInExceptionText) {
return "line " + lineNumber;
}
return "manifest of " + filename + ":" + lineNumber;
}
/**
* Reads the Manifest from the specified InputStream. The entry
* names and attributes read will be merged in with the current
@ -193,7 +224,7 @@ public class Manifest implements Cloneable {
// Line buffer
byte[] lbuf = new byte[512];
// Read the main attributes for the manifest
attr.read(fis, lbuf);
int lineNumber = attr.read(fis, lbuf, jarFilename, 0);
// Total number of entries, attributes read
int ecount = 0, acount = 0;
// Average size of entry attributes
@ -206,8 +237,11 @@ public class Manifest implements Cloneable {
while ((len = fis.readLine(lbuf)) != -1) {
byte c = lbuf[--len];
lineNumber++;
if (c != '\n' && c != '\r') {
throw new IOException("manifest line too long");
throw new IOException("manifest line too long ("
+ getErrorPosition(jarFilename, lineNumber) + ")");
}
if (len > 0 && lbuf[len-1] == '\r') {
--len;
@ -220,7 +254,8 @@ public class Manifest implements Cloneable {
if (name == null) {
name = parseName(lbuf, len);
if (name == null) {
throw new IOException("invalid manifest format");
throw new IOException("invalid manifest format"
+ getErrorPosition(jarFilename, lineNumber) + ")");
}
if (fis.peek() == ' ') {
// name is wrapped
@ -246,7 +281,7 @@ public class Manifest implements Cloneable {
attr = new Attributes(asize);
entries.put(name, attr);
}
attr.read(fis, lbuf);
lineNumber = attr.read(fis, lbuf, jarFilename, lineNumber);
ecount++;
acount += attr.size();
//XXX: Fix for when the average is 0. When it is 0,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -1884,6 +1884,102 @@ public final class Collectors {
(l, r) -> { l.combine(r); return l; }, CH_ID);
}
/**
* Returns a {@code Collector} that is a composite of two downstream collectors.
* Every element passed to the resulting collector is processed by both downstream
* collectors, then their results are merged using the specified merge function
* into the final result.
*
* <p>The resulting collector functions do the following:
*
* <ul>
* <li>supplier: creates a result container that contains result containers
* obtained by calling each collector's supplier
* <li>accumulator: calls each collector's accumulator with its result container
* and the input element
* <li>combiner: calls each collector's combiner with two result containers
* <li>finisher: calls each collector's finisher with its result container,
* then calls the supplied merger and returns its result.
* </ul>
*
* <p>The resulting collector is {@link Collector.Characteristics#UNORDERED} if both downstream
* collectors are unordered and {@link Collector.Characteristics#CONCURRENT} if both downstream
* collectors are concurrent.
*
* @param <T> the type of the input elements
* @param <R1> the result type of the first collector
* @param <R2> the result type of the second collector
* @param <R> the final result type
* @param downstream1 the first downstream collector
* @param downstream2 the second downstream collector
* @param merger the function which merges two results into the single one
* @return a {@code Collector} which aggregates the results of two supplied collectors.
* @since 12
*/
public static <T, R1, R2, R>
Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger) {
return teeing0(downstream1, downstream2, merger);
}
private static <T, A1, A2, R1, R2, R>
Collector<T, ?, R> teeing0(Collector<? super T, A1, R1> downstream1,
Collector<? super T, A2, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger) {
Objects.requireNonNull(downstream1, "downstream1");
Objects.requireNonNull(downstream2, "downstream2");
Objects.requireNonNull(merger, "merger");
Supplier<A1> c1Supplier = Objects.requireNonNull(downstream1.supplier(), "downstream1 supplier");
Supplier<A2> c2Supplier = Objects.requireNonNull(downstream2.supplier(), "downstream2 supplier");
BiConsumer<A1, ? super T> c1Accumulator =
Objects.requireNonNull(downstream1.accumulator(), "downstream1 accumulator");
BiConsumer<A2, ? super T> c2Accumulator =
Objects.requireNonNull(downstream2.accumulator(), "downstream2 accumulator");
BinaryOperator<A1> c1Combiner = Objects.requireNonNull(downstream1.combiner(), "downstream1 combiner");
BinaryOperator<A2> c2Combiner = Objects.requireNonNull(downstream2.combiner(), "downstream2 combiner");
Function<A1, R1> c1Finisher = Objects.requireNonNull(downstream1.finisher(), "downstream1 finisher");
Function<A2, R2> c2Finisher = Objects.requireNonNull(downstream2.finisher(), "downstream2 finisher");
Set<Collector.Characteristics> characteristics;
Set<Collector.Characteristics> c1Characteristics = downstream1.characteristics();
Set<Collector.Characteristics> c2Characteristics = downstream2.characteristics();
if (CH_ID.containsAll(c1Characteristics) || CH_ID.containsAll(c2Characteristics)) {
characteristics = CH_NOID;
} else {
EnumSet<Collector.Characteristics> c = EnumSet.noneOf(Collector.Characteristics.class);
c.addAll(c1Characteristics);
c.retainAll(c2Characteristics);
c.remove(Collector.Characteristics.IDENTITY_FINISH);
characteristics = Collections.unmodifiableSet(c);
}
class PairBox {
A1 left = c1Supplier.get();
A2 right = c2Supplier.get();
void add(T t) {
c1Accumulator.accept(left, t);
c2Accumulator.accept(right, t);
}
PairBox combine(PairBox other) {
left = c1Combiner.apply(left, other.left);
right = c2Combiner.apply(right, other.right);
return this;
}
R get() {
R1 r1 = c1Finisher.apply(left);
R2 r2 = c2Finisher.apply(right);
return merger.apply(r1, r2);
}
}
return new CollectorImpl<>(PairBox::new, PairBox::add, PairBox::combine, PairBox::get, characteristics);
}
/**
* Implementation class used by partitioningBy.
*/

View File

@ -30,43 +30,14 @@ import java.lang.reflect.Constructor;
import java.net.InetSocketAddress;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.Security;
import sun.security.util.SecurityProperties;
public final class SocketExceptions {
private SocketExceptions() {}
/**
* Security or system property which specifies categories of
* (potentially sensitive) information that may be included
* in exception text. This class only defines one category:
* "hostInfo" which represents the hostname and port number
* of the remote peer relating to a socket exception.
* The property value is a comma separated list of
* case insignificant category names.
*/
private static final String enhancedTextPropname = "jdk.includeInExceptions";
private static final boolean enhancedExceptionText = initTextProp();
private static boolean initTextProp() {
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
String val = System.getProperty(enhancedTextPropname);
if (val == null) {
val = Security.getProperty(enhancedTextPropname);
if (val == null)
return false;
}
String[] tokens = val.split(",");
for (String token : tokens) {
if (token.equalsIgnoreCase("hostinfo"))
return true;
}
return false;
}
});
}
private static final boolean enhancedExceptionText =
SecurityProperties.includedInExceptions("hostInfo");
/**
* Utility which takes an exception and returns either the same exception
@ -74,8 +45,9 @@ public final class SocketExceptions {
* and detail message enhanced with addressing information from the
* given InetSocketAddress.
*
* If the system/security property "jdk.net.enhanceExceptionText" is not
* set or is false, then the original exception is returned.
* If the system/security property "jdk.includeInExceptions" is not
* set or does not contain the category hostInfo,
* then the original exception is returned.
*
* Only specific IOException subtypes are supported.
*/

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 SAP SE. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 sun.security.util;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.Security;
public class SecurityProperties {
/**
* Returns the value of the security property propName, which can be overridden
* by a system property of the same name
*
* @param propName the name of the system or security property
* @return the value of the system or security property
*/
public static String privilegedGetOverridable(String propName) {
return AccessController.doPrivileged((PrivilegedAction<String>)
() -> {
String val = System.getProperty(propName);
if (val == null) {
return Security.getProperty(propName);
} else {
return val;
}
});
}
/**
* Returns true in case the system or security property "jdk.includeInExceptions"
* contains the category refName
*
* @param refName the category to check
* @return true in case the system or security property "jdk.includeInExceptions"
* contains refName, false otherwise
*/
public static boolean includedInExceptions(String refName) {
String val = privilegedGetOverridable("jdk.includeInExceptions");
if (val == null) {
return false;
}
String[] tokens = val.split(",");
for (String token : tokens) {
token = token.trim();
if (token.equalsIgnoreCase(refName)) {
return true;
}
}
return false;
}
}

View File

@ -1081,7 +1081,10 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep
# java.nio.channels package will contain enhanced exception
# message information
#
# jar - enables more detailed information in the IOExceptions thrown
# by classes in the java.util.jar package
#
# The property setting in this file can be overridden by a system property of
# the same name, with the same syntax and possible values.
#
#jdk.includeInExceptions=hostInfo
#jdk.includeInExceptions=hostInfo,jar

View File

@ -47,7 +47,7 @@
#ifndef SO_REUSEPORT
#ifdef __linux__
#define SO_REUSEPORT 15
#elif __solaris__
#elif defined(__solaris__)
#define SO_REUSEPORT 0x100e
#elif defined(AIX) || defined(MACOSX)
#define SO_REUSEPORT 0x0200

View File

@ -37,14 +37,14 @@
#include <pthread.h>
/* Also defined in net/linux_close.c */
#define INTERRUPT_SIGNAL (__SIGRTMAX - 2)
#elif _AIX
#elif defined(_AIX)
#include <pthread.h>
/* Also defined in net/aix_close.c */
#define INTERRUPT_SIGNAL (SIGRTMAX - 1)
#elif __solaris__
#elif defined(__solaris__)
#include <thread.h>
#define INTERRUPT_SIGNAL (SIGRTMAX - 2)
#elif _ALLBSD_SOURCE
#elif defined(_ALLBSD_SOURCE)
#include <pthread.h>
/* Also defined in net/bsd_close.c */
#define INTERRUPT_SIGNAL SIGIO

View File

@ -40,7 +40,7 @@
#ifndef SO_REUSEPORT
#ifdef __linux__
#define SO_REUSEPORT 15
#elif __solaris__
#elif defined(__solaris__)
#define SO_REUSEPORT 0x100e
#elif defined(AIX) || defined(MACOSX)
#define SO_REUSEPORT 0x0200

View File

@ -26,9 +26,11 @@
#ifndef macosx_port_awt_debug_h
#define macosx_port_awt_debug_h
#include "jni.h"
#import <Cocoa/Cocoa.h>
bool ShouldPrintVerboseDebugging();
JNIEXPORT bool ShouldPrintVerboseDebugging();
#define kInternalError "java/lang/InternalError"

View File

@ -32,7 +32,7 @@
#import <Cocoa/Cocoa.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h>
@interface NSApplicationAWT : NSApplication <NSUserNotificationCenterDelegate> {
JNIEXPORT @interface NSApplicationAWT : NSApplication <NSUserNotificationCenterDelegate> {
NSString *fApplicationName;
NSWindow *eventTransparentWindow;
NSTimeInterval dummyEventTimestamp;
@ -57,5 +57,5 @@
@end
void OSXAPP_SetApplicationDelegate(id <NSApplicationDelegate> delegate);
JNIEXPORT void OSXAPP_SetApplicationDelegate(id <NSApplicationDelegate> delegate);

View File

@ -23,11 +23,17 @@
* questions.
*/
/*
* Must include this before JavaNativeFoundation.h to get jni.h from build
*/
#include "jni.h"
#include "jni_util.h"
#import <Cocoa/Cocoa.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h>
@interface PropertiesUtilities : NSObject
JNIEXPORT @interface PropertiesUtilities : NSObject
+ (NSString *) javaSystemPropertyForKey:(NSString *)key withEnv:(JNIEnv *)env;

View File

@ -26,6 +26,8 @@
#ifndef __THREADUTILITIES_H
#define __THREADUTILITIES_H
#include "jni.h"
#import <pthread.h>
#import "AWT_debug.h"
@ -135,6 +137,6 @@ __attribute__((visibility("default")))
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait;
@end
void OSXAPP_SetJavaVM(JavaVM *vm);
JNIEXPORT void OSXAPP_SetJavaVM(JavaVM *vm);
#endif /* __THREADUTILITIES_H */

View File

@ -433,7 +433,9 @@ public class Flags {
SYSTEM_MODULE(Flags.SYSTEM_MODULE),
DEPRECATED_ANNOTATION(Flags.DEPRECATED_ANNOTATION),
DEPRECATED_REMOVAL(Flags.DEPRECATED_REMOVAL),
HAS_RESOURCE(Flags.HAS_RESOURCE);
HAS_RESOURCE(Flags.HAS_RESOURCE),
POTENTIALLY_AMBIGUOUS(Flags.POTENTIALLY_AMBIGUOUS),
ANONCONSTR_BASED(Flags.ANONCONSTR_BASED);
Flag(long flag) {
this.value = flag;

View File

@ -166,10 +166,10 @@ public class Analyzer {
res = EnumSet.allOf(AnalyzerMode.class);
}
for (AnalyzerMode mode : values()) {
if (modes.contains(mode.opt)) {
res.add(mode);
} else if (modes.contains("-" + mode.opt) || !mode.feature.allowedInSource(source)) {
if (modes.contains("-" + mode.opt) || !mode.feature.allowedInSource(source)) {
res.remove(mode);
} else if (modes.contains(mode.opt)) {
res.add(mode);
}
}
return res;

View File

@ -2689,12 +2689,14 @@ public class Attr extends JCTree.Visitor {
*/
@Override
public void visitLambda(final JCLambda that) {
boolean wrongContext = false;
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
//lambda only allowed in assignment or method invocation/cast context
log.error(that.pos(), Errors.UnexpectedLambda);
}
resultInfo = recoveryInfo;
wrongContext = true;
}
//create an environment for attribution of the lambda expression
final Env<AttrContext> localEnv = lambdaEnv(that, env);
@ -2811,7 +2813,8 @@ public class Attr extends JCTree.Visitor {
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, currentTarget);
}
result = check(that, currentTarget, KindSelector.VAL, resultInfo);
result = wrongContext ? that.type = types.createErrorType(pt())
: check(that, currentTarget, KindSelector.VAL, resultInfo);
} catch (Types.FunctionDescriptorLookupError ex) {
JCDiagnostic cause = ex.getDiagnostic();
resultInfo.checkContext.report(that, cause);
@ -5342,14 +5345,6 @@ public class Attr extends JCTree.Visitor {
super.visitUnary(that);
}
@Override
public void visitLambda(JCLambda that) {
super.visitLambda(that);
if (that.target == null) {
that.target = syms.unknownType;
}
}
@Override
public void visitReference(JCMemberReference that) {
super.visitReference(that);
@ -5357,9 +5352,6 @@ public class Attr extends JCTree.Visitor {
that.sym = new MethodSymbol(0, names.empty, dummyMethodType(),
syms.noSymbol);
}
if (that.target == null) {
that.target = syms.unknownType;
}
}
}
// </editor-fold>

View File

@ -50,8 +50,9 @@ import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
@ -63,6 +64,8 @@ import java.util.Map;
import java.util.MissingResourceException;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.NestingKind;
@ -182,7 +185,7 @@ public class Main {
public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException {
Path file = getFile(args);
Context context = new Context();
Context context = new Context(file.toAbsolutePath());
String mainClassName = compile(file, getJavacOpts(runtimeArgs), context);
String[] appArgs = Arrays.copyOfRange(args, 1, args.length);
@ -193,7 +196,7 @@ public class Main {
* Returns the path for the filename found in the first of an array of arguments.
*
* @param args the array
* @return the path
* @return the path, as given in the array of args
* @throws Fault if there is a problem determining the path, or if the file does not exist
*/
private Path getFile(String[] args) throws Fault {
@ -396,12 +399,10 @@ public class Main {
*/
private void execute(String mainClassName, String[] appArgs, Context context)
throws Fault, InvocationTargetException {
System.setProperty("jdk.launcher.sourcefile", context.file.toString());
ClassLoader cl = context.getClassLoader(ClassLoader.getSystemClassLoader());
try {
Class<?> appClass = Class.forName(mainClassName, true, cl);
if (appClass.getClassLoader() != cl) {
throw new Fault(Errors.UnexpectedClass(mainClassName));
}
Method main = appClass.getDeclaredMethod("main", String[].class);
int PUBLIC_STATIC = Modifier.PUBLIC | Modifier.STATIC;
if ((main.getModifiers() & PUBLIC_STATIC) != PUBLIC_STATIC) {
@ -481,14 +482,19 @@ public class Main {
* a class loader.
*/
private static class Context {
private Map<String, byte[]> inMemoryClasses = new HashMap<>();
private final Path file;
private final Map<String, byte[]> inMemoryClasses = new HashMap<>();
Context(Path file) {
this.file = file;
}
JavaFileManager getFileManager(StandardJavaFileManager delegate) {
return new MemoryFileManager(inMemoryClasses, delegate);
}
ClassLoader getClassLoader(ClassLoader parent) {
return new MemoryClassLoader(inMemoryClasses, parent);
return new MemoryClassLoader(inMemoryClasses, parent, file);
}
}
@ -535,36 +541,126 @@ public class Main {
}
/**
* An in-memory classloader, that uses an in-memory cache written by {@link MemoryFileManager}.
* An in-memory classloader, that uses an in-memory cache of classes written by
* {@link MemoryFileManager}.
*
* <p>The classloader uses the standard parent-delegation model, just providing
* {@code findClass} to find classes in the in-memory cache.
* <p>The classloader inverts the standard parent-delegation model, giving preference
* to classes defined in the source file before classes known to the parent (such
* as any like-named classes that might be found on the application class path.)
*/
private static class MemoryClassLoader extends ClassLoader {
/**
* The map of classes known to this class loader, indexed by
* The map of all classes found in the source file, indexed by
* {@link ClassLoader#name binary name}.
*/
private final Map<String, byte[]> map;
private final Map<String, byte[]> sourceFileClasses;
MemoryClassLoader(Map<String, byte[]> map, ClassLoader parent) {
/**
* A minimal protection domain, specifying a code source of the source file itself,
* used for classes found in the source file and defined by this loader.
*/
private final ProtectionDomain domain;
MemoryClassLoader(Map<String, byte[]> sourceFileClasses, ClassLoader parent, Path file) {
super(parent);
this.map = map;
this.sourceFileClasses = sourceFileClasses;
CodeSource codeSource;
try {
codeSource = new CodeSource(file.toUri().toURL(), (CodeSigner[]) null);
} catch (MalformedURLException e) {
codeSource = null;
}
domain = new ProtectionDomain(codeSource, null, this, null);
}
/**
* Override loadClass to check for classes defined in the source file
* before checking for classes in the parent class loader,
* including those on the classpath.
*
* {@code loadClass(String name)} calls this method, and so will have the same behavior.
*
* @param name the name of the class to load
* @param resolve whether or not to resolve the class
* @return the class
* @throws ClassNotFoundException if the class is not found
*/
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
if (sourceFileClasses.containsKey(name)) {
c = findClass(name);
} else {
c = getParent().loadClass(name);
}
if (resolve) {
resolveClass(c);
}
}
return c;
}
}
/**
* Override getResource to check for resources (i.e. class files) defined in the
* source file before checking resources in the parent class loader,
* including those on the class path.
*
* {@code getResourceAsStream(String name)} calls this method,
* and so will have the same behavior.
*
* @param name the name of the resource
* @return a URL for the resource, or null if not found
*/
@Override
public URL getResource(String name) {
if (sourceFileClasses.containsKey(toBinaryName(name))) {
return findResource(name);
} else {
return getParent().getResource(name);
}
}
/**
* Override getResources to check for resources (i.e. class files) defined in the
* source file before checking resources in the parent class loader,
* including those on the class path.
*
* @param name the name of the resource
* @return an enumeration of the resources in this loader and in the application class loader
*/
@Override
public Enumeration<URL> getResources(String name) throws IOException {
URL u = findResource(name);
Enumeration<URL> e = getParent().getResources(name);
if (u == null) {
return e;
} else {
List<URL> list = new ArrayList<>();
list.add(u);
while (e.hasMoreElements()) {
list.add(e.nextElement());
}
return Collections.enumeration(list);
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = map.get(name);
byte[] bytes = sourceFileClasses.get(name);
if (bytes == null) {
throw new ClassNotFoundException(name);
}
return defineClass(name, bytes, 0, bytes.length);
return defineClass(name, bytes, 0, bytes.length, domain);
}
@Override
public URL findResource(String name) {
String binaryName = toBinaryName(name);
if (binaryName == null || map.get(binaryName) == null) {
if (binaryName == null || sourceFileClasses.get(binaryName) == null) {
return null;
}
@ -628,7 +724,7 @@ public class Main {
if (!u.getProtocol().equalsIgnoreCase(PROTOCOL)) {
throw new IllegalArgumentException(u.toString());
}
return new MemoryURLConnection(u, map.get(toBinaryName(u.getPath())));
return new MemoryURLConnection(u, sourceFileClasses.get(toBinaryName(u.getPath())));
}
}

View File

@ -328,7 +328,7 @@ public enum Option {
ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER),
SOURCE("-source", "opt.arg.release", "opt.source", STANDARD, BASIC) {
SOURCE("--source -source", "opt.arg.release", "opt.source", STANDARD, BASIC) {
@Override
public void process(OptionHelper helper, String option, String operand) throws InvalidValueException {
Source source = Source.lookup(operand);
@ -349,7 +349,7 @@ public enum Option {
}
},
TARGET("-target", "opt.arg.release", "opt.target", STANDARD, BASIC) {
TARGET("--target -target", "opt.arg.release", "opt.target", STANDARD, BASIC) {
@Override
public void process(OptionHelper helper, String option, String operand) throws InvalidValueException {
Target target = Target.lookup(operand);

View File

@ -108,10 +108,6 @@ launcher.err.main.not.void=\
launcher.err.cant.find.class=\
can''t find class: {0}
# 0: string
launcher.err.unexpected.class=\
class found on application class path: {0}
# 0: string
launcher.err.cant.find.main.method=\
can''t find main(String[]) method in class: {0}

View File

@ -380,8 +380,8 @@ public class Start extends ToolOption.Helper {
String platformString = compOpts.get("--release");
if (platformString != null) {
if (compOpts.isSet("-source")) {
usageError("main.release.bootclasspath.conflict", "-source");
if (compOpts.isSet(Option.SOURCE.primaryName)) {
usageError("main.release.bootclasspath.conflict", Option.SOURCE.primaryName);
}
if (fileManagerOpts.containsKey(Option.BOOT_CLASS_PATH)) {
usageError("main.release.bootclasspath.conflict", Option.BOOT_CLASS_PATH.getPrimaryName());

View File

@ -172,6 +172,13 @@ public enum ToolOption {
},
SOURCE("-source", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt("--source", arg);
}
},
SOURCE2("--source", true) {
@Override
public void process(Helper helper, String arg) {
helper.setCompilerOpt(opt, arg);

View File

@ -208,12 +208,6 @@ public class HtmlConfiguration extends BaseConfiguration {
*/
public HtmlVersion htmlVersion = null;
/**
* Flag to enable/disable use of module directories when generating docs for modules
* Default: on (module directories are enabled).
*/
public boolean useModuleDirectories = true;
/**
* Collected set of doclint options
*/
@ -840,13 +834,6 @@ public class HtmlConfiguration extends BaseConfiguration {
}
return true;
}
},
new XOption(resources, "--no-module-directories") {
@Override
public boolean process(String option, List<String> args) {
useModuleDirectories = false;
return true;
}
}
};
Set<Doclet.Option> oset = new TreeSet<>();

View File

@ -355,12 +355,24 @@ public class HtmlDocletWriter {
/**
* Returns a TagletWriter that knows how to write HTML.
*
* @param isFirstSentence true if we want to write the first sentence
* @return a TagletWriter that knows how to write HTML.
*/
public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
return new TagletWriterImpl(this, isFirstSentence);
}
/**
* Returns a TagletWriter that knows how to write HTML.
*
* @param isFirstSentence true if we want to write the first sentence
* @param inSummary true if tags are to be added in a summary section
* @return a TagletWriter
*/
public TagletWriter getTagletWriterInstance(boolean isFirstSentence, boolean inSummary) {
return new TagletWriterImpl(this, isFirstSentence, inSummary);
}
/**
* Get Package link, with target frame.
*
@ -610,7 +622,7 @@ public class HtmlDocletWriter {
return links.createLink(pathString(packageElement, DocPaths.PACKAGE_SUMMARY),
label);
} else {
DocLink crossPkgLink = getCrossPackageLink(utils.getPackageName(packageElement));
DocLink crossPkgLink = getCrossPackageLink(packageElement);
if (crossPkgLink != null) {
return links.createLink(crossPkgLink, label);
} else {
@ -693,11 +705,10 @@ public class HtmlDocletWriter {
/*************************************************************
* Return a class cross link to external class documentation.
* The name must be fully qualified to determine which package
* the class is in. The -link option does not allow users to
* The -link option does not allow users to
* link to external classes in the "default" package.
*
* @param qualifiedClassName the qualified name of the external class.
* @param classElement the class element
* @param refMemName the name of the member being referenced. This should
* be null or empty string if no member is being referenced.
* @param label the label for the external link.
@ -705,19 +716,15 @@ public class HtmlDocletWriter {
* @param code true if the label should be code font.
* @return the link
*/
public Content getCrossClassLink(String qualifiedClassName, String refMemName,
public Content getCrossClassLink(TypeElement classElement, String refMemName,
Content label, boolean strong, boolean code) {
String className = "";
String packageName = qualifiedClassName == null ? "" : qualifiedClassName;
int periodIndex;
while ((periodIndex = packageName.lastIndexOf('.')) != -1) {
className = packageName.substring(periodIndex + 1, packageName.length()) +
(className.length() > 0 ? "." + className : "");
if (classElement != null) {
String className = utils.getSimpleName(classElement);
PackageElement packageElement = utils.containingPackage(classElement);
Content defaultLabel = new StringContent(className);
if (code)
defaultLabel = HtmlTree.CODE(defaultLabel);
packageName = packageName.substring(0, periodIndex);
if (getCrossPackageLink(packageName) != null) {
if (getCrossPackageLink(packageElement) != null) {
/*
The package exists in external documentation, so link to the external
class (assuming that it exists). This is definitely a limitation of
@ -725,13 +732,13 @@ public class HtmlDocletWriter {
exists, but no way to determine if the external class exists. We just
have to assume that it does.
*/
DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot,
DocLink link = configuration.extern.getExternalLink(packageElement, pathToRoot,
className + ".html", refMemName);
return links.createLink(link,
(label == null) || label.isEmpty() ? defaultLabel : label,
strong,
resources.getText("doclet.Href_Class_Or_Interface_Title", packageName),
"", true);
resources.getText("doclet.Href_Class_Or_Interface_Title",
utils.getPackageName(packageElement)), "", true);
}
}
return null;
@ -744,14 +751,14 @@ public class HtmlDocletWriter {
return configuration.extern.isExternal(typeElement);
}
public DocLink getCrossPackageLink(String pkgName) {
return configuration.extern.getExternalLink(pkgName, pathToRoot,
public DocLink getCrossPackageLink(PackageElement element) {
return configuration.extern.getExternalLink(element, pathToRoot,
DocPaths.PACKAGE_SUMMARY.getPath());
}
public DocLink getCrossModuleLink(String mdleName) {
return configuration.extern.getExternalLink(mdleName, pathToRoot,
docPaths.moduleSummary(mdleName).getPath());
public DocLink getCrossModuleLink(ModuleElement element) {
return configuration.extern.getExternalLink(element, pathToRoot,
docPaths.moduleSummary(utils.getModuleName(element)).getPath());
}
/**
@ -1024,17 +1031,13 @@ public class HtmlDocletWriter {
return getPackageLink(refPackage, label);
} else {
// @see is not referencing an included class, module or package. Check for cross links.
Content classCrossLink;
DocLink elementCrossLink = (configuration.extern.isModule(refClassName))
? getCrossModuleLink(refClassName) : getCrossPackageLink(refClassName);
? getCrossModuleLink(utils.elementUtils.getModuleElement(refClassName)) :
(refPackage != null) ? getCrossPackageLink(refPackage) : null;
if (elementCrossLink != null) {
// Element cross link found
return links.createLink(elementCrossLink,
(label.isEmpty() ? text : label), true);
} else if ((classCrossLink = getCrossClassLink(refClassName,
refMemName, label, false, !isLinkPlain)) != null) {
// Class cross link found (possibly to a member in the class)
return classCrossLink;
} else {
// No cross link found so print warning
messages.warning(ch.getDocTreePath(see),
@ -1136,7 +1139,7 @@ public class HtmlDocletWriter {
public void addInlineComment(Element element, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> description = ch.getDescription(configuration, tag);
addCommentTags(element, tag, description, false, false, htmltree);
addCommentTags(element, tag, description, false, false, false, htmltree);
}
/**
@ -1160,7 +1163,7 @@ public class HtmlDocletWriter {
*/
public void addInlineDeprecatedComment(Element e, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(e);
addCommentTags(e, ch.getBody(configuration, tag), true, false, htmltree);
addCommentTags(e, ch.getBody(configuration, tag), true, false, false, htmltree);
}
/**
@ -1181,13 +1184,13 @@ public class HtmlDocletWriter {
* @param htmltree the documentation tree to which the summary will be added
*/
public void addSummaryComment(Element element, List<? extends DocTree> firstSentenceTags, Content htmltree) {
addCommentTags(element, firstSentenceTags, false, true, htmltree);
addCommentTags(element, firstSentenceTags, false, true, true, htmltree);
}
public void addSummaryDeprecatedComment(Element element, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> body = ch.getBody(configuration, tag);
addCommentTags(element, ch.getFirstSentenceTrees(configuration, body), true, true, htmltree);
addCommentTags(element, ch.getFirstSentenceTrees(configuration, body), true, true, true, htmltree);
}
/**
@ -1197,7 +1200,7 @@ public class HtmlDocletWriter {
* @param htmltree the documentation tree to which the inline comments will be added
*/
public void addInlineComment(Element element, Content htmltree) {
addCommentTags(element, utils.getFullBody(element), false, false, htmltree);
addCommentTags(element, utils.getFullBody(element), false, false, false, htmltree);
}
/**
@ -1207,11 +1210,12 @@ public class HtmlDocletWriter {
* @param tags the first sentence tags for the doc
* @param depr true if it is deprecated
* @param first true if the first sentence tags should be added
* @param inSummary true if the comment tags are added into the summary section
* @param htmltree the documentation tree to which the comment tags will be added
*/
private void addCommentTags(Element element, List<? extends DocTree> tags, boolean depr,
boolean first, Content htmltree) {
addCommentTags(element, null, tags, depr, first, htmltree);
boolean first, boolean inSummary, Content htmltree) {
addCommentTags(element, null, tags, depr, first, inSummary, htmltree);
}
/**
@ -1222,15 +1226,16 @@ public class HtmlDocletWriter {
* @param tags the first sentence tags for the doc
* @param depr true if it is deprecated
* @param first true if the first sentence tags should be added
* @param inSummary true if the comment tags are added into the summary section
* @param htmltree the documentation tree to which the comment tags will be added
*/
private void addCommentTags(Element element, DocTree holderTag, List<? extends DocTree> tags, boolean depr,
boolean first, Content htmltree) {
boolean first, boolean inSummary, Content htmltree) {
if(configuration.nocomment){
return;
}
Content div;
Content result = commentTagsToContent(null, element, tags, first);
Content result = commentTagsToContent(null, element, tags, first, inSummary);
if (depr) {
div = HtmlTree.DIV(HtmlStyle.deprecationComment, result);
htmltree.addContent(div);
@ -1276,10 +1281,10 @@ public class HtmlDocletWriter {
private boolean commentRemoved = false;
/**
* Converts inline tags and text to text strings, expanding the
* Converts inline tags and text to Content, expanding the
* inline tags along the way. Called wherever text can contain
* an inline tag, such as in comments or in free-form text arguments
* to non-inline tags.
* to block tags.
*
* @param holderTag specific tag where comment resides
* @param element specific element where comment resides
@ -1290,6 +1295,25 @@ public class HtmlDocletWriter {
*/
public Content commentTagsToContent(DocTree holderTag, Element element,
List<? extends DocTree> tags, boolean isFirstSentence) {
return commentTagsToContent(holderTag, element, tags, isFirstSentence, false);
}
/**
* Converts inline tags and text to text strings, expanding the
* inline tags along the way. Called wherever text can contain
* an inline tag, such as in comments or in free-form text arguments
* to block tags.
*
* @param holderTag specific tag where comment resides
* @param element specific element where comment resides
* @param tags array of text tags and inline tags (often alternating)
present in the text of interest for this element
* @param isFirstSentence true if text is first sentence
* @param inSummary if the comment tags are added into the summary section
* @return a Content object
*/
public Content commentTagsToContent(DocTree holderTag, Element element,
List<? extends DocTree> tags, boolean isFirstSentence, boolean inSummary) {
final Content result = new ContentBuilder() {
@Override
@ -1454,7 +1478,7 @@ public class HtmlDocletWriter {
public Boolean visitIndex(IndexTree node, Content p) {
Content output = TagletWriter.getInlineTagOutput(element,
configuration.tagletManager, holderTag, tag,
getTagletWriterInstance(isFirstSentence));
getTagletWriterInstance(isFirstSentence, inSummary));
if (output != null) {
result.addContent(output);
}

View File

@ -111,7 +111,7 @@ public class LinkFactoryImpl extends LinkFactory {
}
} else {
Content crossLink = m_writer.getCrossClassLink(
typeElement.getQualifiedName().toString(), classLinkInfo.where,
typeElement, classLinkInfo.where,
label, classLinkInfo.isStrong, true);
if (crossLink != null) {
link.addContent(crossLink);

View File

@ -396,14 +396,14 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
(utils.getBlockTags(mdle, DocTree.Kind.PROVIDES)).forEach((tree) -> {
TypeElement t = ch.getServiceType(configuration, tree);
if (t != null) {
providesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false));
providesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false, true));
}
});
// Generate the map of all services listed using @uses, and the description.
(utils.getBlockTags(mdle, DocTree.Kind.USES)).forEach((tree) -> {
TypeElement t = ch.getServiceType(configuration, tree);
if (t != null) {
usesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false));
usesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(configuration, tree), false, true));
}
});
}

View File

@ -71,12 +71,18 @@ public class TagletWriterImpl extends TagletWriter {
private final HtmlDocletWriter htmlWriter;
private final HtmlConfiguration configuration;
private final Utils utils;
private final boolean inSummary;
public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence) {
this(htmlWriter, isFirstSentence, false);
}
public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence, boolean inSummary) {
super(isFirstSentence);
this.htmlWriter = htmlWriter;
configuration = htmlWriter.configuration;
this.utils = configuration.utils;
this.inSummary = inSummary;
}
/**
@ -107,53 +113,58 @@ public class TagletWriterImpl extends TagletWriter {
String desc = ch.getText(itt.getDescription());
String anchorName = htmlWriter.links.getName(tagText);
Content result = HtmlTree.A_ID(HtmlStyle.searchTagResult, anchorName, new StringContent(tagText));
if (configuration.createindex && !tagText.isEmpty()) {
SearchIndexItem si = new SearchIndexItem();
si.setLabel(tagText);
si.setDescription(desc);
DocPaths docPaths = configuration.docPaths;
new SimpleElementVisitor9<Void, Void>() {
@Override
public Void visitModule(ModuleElement e, Void p) {
si.setUrl(docPaths.moduleSummary(e).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(element));
return null;
}
Content result = null;
if (isFirstSentence && inSummary) {
result = new StringContent(tagText);
} else {
result = HtmlTree.A_ID(HtmlStyle.searchTagResult, anchorName, new StringContent(tagText));
if (configuration.createindex && !tagText.isEmpty()) {
SearchIndexItem si = new SearchIndexItem();
si.setLabel(tagText);
si.setDescription(desc);
DocPaths docPaths = configuration.docPaths;
new SimpleElementVisitor9<Void, Void>() {
@Override
public Void visitModule(ModuleElement e, Void p) {
si.setUrl(docPaths.moduleSummary(e).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(element));
return null;
}
@Override
public Void visitPackage(PackageElement e, Void p) {
si.setUrl(docPaths.forPackage(e).getPath()
+ "/" + DocPaths.PACKAGE_SUMMARY.getPath() + "#" + anchorName);
si.setHolder(utils.getSimpleName(element));
return null;
}
@Override
public Void visitPackage(PackageElement e, Void p) {
si.setUrl(docPaths.forPackage(e).getPath()
+ "/" + DocPaths.PACKAGE_SUMMARY.getPath() + "#" + anchorName);
si.setHolder(utils.getSimpleName(element));
return null;
}
@Override
public Void visitType(TypeElement e, Void p) {
si.setUrl(docPaths.forClass(e).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(e));
return null;
}
@Override
public Void visitType(TypeElement e, Void p) {
si.setUrl(docPaths.forClass(e).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(e));
return null;
}
@Override
public Void visitVariable(VariableElement e, Void p) {
TypeElement te = utils.getEnclosingTypeElement(e);
si.setUrl(docPaths.forClass(te).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(e) + "." + utils.getSimpleName(e));
return null;
}
@Override
public Void visitVariable(VariableElement e, Void p) {
TypeElement te = utils.getEnclosingTypeElement(e);
si.setUrl(docPaths.forClass(te).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(e) + "." + utils.getSimpleName(e));
return null;
}
@Override
protected Void defaultAction(Element e, Void p) {
TypeElement te = utils.getEnclosingTypeElement(e);
si.setUrl(docPaths.forClass(te).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(e));
return null;
}
}.visit(element);
si.setCategory(configuration.getContent("doclet.SearchTags").toString());
configuration.tagSearchIndex.add(si);
@Override
protected Void defaultAction(Element e, Void p) {
TypeElement te = utils.getEnclosingTypeElement(e);
si.setUrl(docPaths.forClass(te).getPath() + "#" + anchorName);
si.setHolder(utils.getFullyQualifiedName(e));
return null;
}
}.visit(element);
si.setCategory(configuration.getContent("doclet.SearchTags").toString());
configuration.tagSearchIndex.add(si);
}
}
return result;
}
@ -236,7 +247,7 @@ public class TagletWriterImpl extends TagletWriter {
body.addContent(HtmlTree.CODE(new RawHtml(paramName)));
body.addContent(" - ");
List<? extends DocTree> description = ch.getDescription(configuration, paramTag);
body.addContent(htmlWriter.commentTagsToContent(paramTag, element, description, false));
body.addContent(htmlWriter.commentTagsToContent(paramTag, element, description, false, inSummary));
HtmlTree result = HtmlTree.DD(body);
return result;
}
@ -264,7 +275,7 @@ public class TagletWriterImpl extends TagletWriter {
result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.returnLabel,
new StringContent(configuration.getText("doclet.Returns")))));
result.addContent(HtmlTree.DD(htmlWriter.commentTagsToContent(
returnTag, element, ch.getDescription(configuration, returnTag), false)));
returnTag, element, ch.getDescription(configuration, returnTag), false, inSummary)));
return result;
}
@ -333,7 +344,7 @@ public class TagletWriterImpl extends TagletWriter {
body.addContent(", ");
}
List<? extends DocTree> bodyTags = ch.getBody(configuration, simpleTag);
body.addContent(htmlWriter.commentTagsToContent(simpleTag, element, bodyTags, false));
body.addContent(htmlWriter.commentTagsToContent(simpleTag, element, bodyTags, false, inSummary));
many = true;
}
result.addContent(HtmlTree.DD(body));
@ -348,7 +359,7 @@ public class TagletWriterImpl extends TagletWriter {
result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.simpleTagLabel, new RawHtml(header))));
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> description = ch.getDescription(configuration, simpleTag);
Content body = htmlWriter.commentTagsToContent(simpleTag, element, description, false);
Content body = htmlWriter.commentTagsToContent(simpleTag, element, description, false, inSummary);
result.addContent(HtmlTree.DD(body));
return result;
}
@ -382,7 +393,7 @@ public class TagletWriterImpl extends TagletWriter {
}
body.addContent(HtmlTree.CODE(excName));
List<? extends DocTree> description = ch.getDescription(configuration, throwsTag);
Content desc = htmlWriter.commentTagsToContent(throwsTag, element, description, false);
Content desc = htmlWriter.commentTagsToContent(throwsTag, element, description, false, inSummary);
if (desc != null && !desc.isEmpty()) {
body.addContent(" - ");
body.addContent(desc);
@ -429,7 +440,7 @@ public class TagletWriterImpl extends TagletWriter {
public Content commentTagsToOutput(DocTree holderTag,
Element holder, List<? extends DocTree> tags, boolean isFirstSentence) {
return htmlWriter.commentTagsToContent(holderTag, holder,
tags, isFirstSentence);
tags, isFirstSentence, inSummary);
}
/**

View File

@ -866,8 +866,7 @@ public class Navigation {
contents.packageLabel)));
} else {
DocLink crossPkgLink = configuration.extern.getExternalLink(
configuration.utils.getPackageName(packageElement), pathToRoot,
DocPaths.PACKAGE_SUMMARY.getPath());
packageElement, pathToRoot, DocPaths.PACKAGE_SUMMARY.getPath());
if (crossPkgLink != null) {
tree.addContent(HtmlTree.LI(links.createLink(crossPkgLink, contents.packageLabel)));
} else {

View File

@ -295,6 +295,11 @@ public abstract class BaseConfiguration {
// A list of pairs containing urls and package list
private final List<Pair<String, String>> linkOfflineList = new ArrayList<>();
/**
* Flag to enable/disable use of module directories when generating docs for modules
* Default: on (module directories are enabled).
*/
public boolean useModuleDirectories = true;
public boolean dumpOnError = false;
@ -740,6 +745,13 @@ public abstract class BaseConfiguration {
return true;
}
},
new XOption(resources, "--no-module-directories") {
@Override
public boolean process(String option, List<String> args) {
useModuleDirectories = false;
return true;
}
}
};
Set<Doclet.Option> set = new TreeSet<>();
set.addAll(Arrays.asList(options));

View File

@ -226,16 +226,15 @@ doclet.Enum_Constant=Enum Constant
doclet.Description=Description
doclet.ConstantField=Constant Field
doclet.Value=Value
doclet.linkMismatch_PackagedLinkedtoModule=The code being documented uses packages in the unnamed module, \
but the packages defined in {0} are in named modules.
doclet.linkMismatch_ModuleLinkedtoPackage=The code being documented uses modules but the packages defined \
in {0} are in the unnamed module.
#Documentation for Enums
doclet.enum_values_doc.fullbody=\
Returns an array containing the constants of this enum type, in\n\
the order they are declared. This method may be used to iterate\n\
over the constants as follows:\n\
<pre>\n\
for ({0} c : {0}.values())\n\
&nbsp; System.out.println(c);\n\
</pre>
the order they are declared.
doclet.enum_values_doc.return=\
an array containing the constants of this enum type, in the order they are declared

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