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 8f594f75e0547d4ca16649cb3501659e3155e81b jdk-12+10
f0f5d23449d31f1b3580c8a73313918cafeaefd7 jdk-12+11 f0f5d23449d31f1b3580c8a73313918cafeaefd7 jdk-12+11
15094d12a632f452a2064318a4e416d0c7a9ce0c jdk-12+12 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)) $1_JTREG_BASIC_OPTIONS += $$(addprefix -exclude:, $$($1_JTREG_PROBLEM_LIST))
endif endif
ifneq ($$(JIB_JAR), ) ifneq ($$(JIB_HOME), )
$1_JTREG_BASIC_OPTIONS += -cpa:$$(JIB_JAR) $1_JTREG_BASIC_OPTIONS += -e:JIB_HOME=$$(JIB_HOME)
endif endif
$1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_GRAAL_DIR=${TEST_IMAGE_DIR}/hotspot/jtreg/graal $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@ XATTR:=@XATTR@
JT_HOME:=@JT_HOME@ JT_HOME:=@JT_HOME@
JTREGEXE:=@JTREGEXE@ JTREGEXE:=@JTREGEXE@
JIB_JAR:=@JIB_JAR@ JIB_HOME:=@JIB_HOME@
XCODEBUILD=@XCODEBUILD@ XCODEBUILD=@XCODEBUILD@
DTRACE := @DTRACE@ DTRACE := @DTRACE@
FIXPATH:=@FIXPATH@ FIXPATH:=@FIXPATH@

View File

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

View File

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

View File

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

View File

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

View File

@ -46,11 +46,9 @@ ifeq ($(TOOLCHAIN_TYPE), gcc)
LDFLAGS_JDKLIB += -Wl,--exclude-libs,ALL LDFLAGS_JDKLIB += -Wl,--exclude-libs,ALL
EXPORT_ALL_SYMBOLS := -fvisibility=default EXPORT_ALL_SYMBOLS := -fvisibility=default
else ifeq ($(TOOLCHAIN_TYPE), clang) else ifeq ($(TOOLCHAIN_TYPE), clang)
ifneq ($(OPENJDK_TARGET_OS), macosx) CFLAGS_JDKLIB += -fvisibility=hidden
CFLAGS_JDKLIB += -fvisibility=hidden CXXFLAGS_JDKLIB += -fvisibility=hidden
CXXFLAGS_JDKLIB += -fvisibility=hidden EXPORT_ALL_SYMBOLS := -fvisibility=default
EXPORT_ALL_SYMBOLS := -fvisibility=default
endif
else ifeq ($(TOOLCHAIN_TYPE), solstudio) else ifeq ($(TOOLCHAIN_TYPE), solstudio)
CFLAGS_JDKLIB += -xldscope=hidden CFLAGS_JDKLIB += -xldscope=hidden
CXXFLAGS_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); 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) { void LIR_Assembler::emit_op3(LIR_Op3* op) {
switch (op->code()) { switch (op->code()) {
case lir_idiv: case lir_idiv:
arithmetic_idiv(op, false);
break;
case lir_irem: 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; break;
case lir_fmad: case lir_fmad:
__ fmaddd(op->result_opr()->as_double_reg(), __ 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()) { } 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); 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) { switch (code) {
case lir_add: __ add(dreg, lreg_lo, c); break; case lir_add:
case lir_sub: __ sub(dreg, lreg_lo, c); break; 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: default:
ShouldNotReachHere(); 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) { 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()) { if (left->is_single_cpu()) {
assert(dest->is_single_cpu(), "expect single result reg"); assert(dest->is_single_cpu(), "expect single result reg");
__ negw(dest->as_register(), left->as_register()); __ negw(dest->as_register(), left->as_register());

View File

@ -75,8 +75,6 @@ friend class ArrayCopyStub;
_deopt_handler_size = 7 * NativeInstruction::instruction_size _deopt_handler_size = 7 * NativeInstruction::instruction_size
}; };
void arithmetic_idiv(LIR_Op3* op, bool is_irem);
public: public:
void store_parameter(Register r, int offset_from_esp_in_words); 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) { 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(); left.load_item();
right.load_item(); bool need_zero_check = true;
if (right.is_constant()) {
__ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0)); jlong c = right.get_jlong_constant();
__ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info)); // 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); rlock_result(x);
switch (x->op()) { 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 // do not need to load right, as we can handle stack and constants
if (x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem) { if (x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem) {
right_arg->load_item();
rlock_result(x); 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 ill = LIR_OprFact::illegalOpr;
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);
if (x->op() == Bytecodes::_irem) { 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) { } 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) { } 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; 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) { address MacroAssembler::ic_call(address entry, jint method_index) {
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
// address const_ptr = long_constant((jlong)Universe::non_oop_word()); // 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); void resolve_jobject(Register value, Register thread, Register tmp);
// C 'boolean' to Java boolean: x == 0 ? 0 : 1
void c2bool(Register x);
// oop manipulations // oop manipulations
void load_klass(Register dst, Register src); void load_klass(Register dst, Register src);
void store_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. // Unpack native results.
switch (ret_type) { 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_CHAR : __ ubfx(r0, r0, 0, 16); break;
case T_BYTE : __ sbfx(r0, r0, 0, 8); break; case T_BYTE : __ sbfx(r0, r0, 0, 8); break;
case T_SHORT : __ sbfx(r0, r0, 0, 16); break; case T_SHORT : __ sbfx(r0, r0, 0, 16); break;

View File

@ -557,7 +557,7 @@ address TemplateInterpreterGenerator::generate_result_handler_for(
BasicType type) { BasicType type) {
address entry = __ pc(); address entry = __ pc();
switch (type) { switch (type) {
case T_BOOLEAN: __ uxtb(r0, r0); break; case T_BOOLEAN: __ c2bool(r0); break;
case T_CHAR : __ uxth(r0, r0); break; case T_CHAR : __ uxth(r0, r0); break;
case T_BYTE : __ sxtb(r0, r0); break; case T_BYTE : __ sxtb(r0, r0); break;
case T_SHORT : __ sxth(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()) { if (left->is_single_cpu()) {
assert (dest->type() == T_INT, "unexpected result type"); 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"); assert(left->is_register(), "can only handle registers");
if (left->is_single_cpu()) { 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. 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"); assert(left->is_register(), "can only handle registers");
if (left->is_single_cpu()) { 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"); assert(left->is_register(), "can only handle registers");
if (left->is_single_cpu()) { 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 // Andn packed integers
void pandn(XMMRegister dst, XMMRegister src); void pandn(XMMRegister dst, XMMRegister src);
void vpandn(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
// Or packed integers // Or packed integers
void por(XMMRegister dst, XMMRegister src); void por(XMMRegister dst, XMMRegister src);
@ -2134,6 +2135,7 @@ private:
void vextracti32x4(Address dst, XMMRegister src, uint8_t imm8); void vextracti32x4(Address dst, XMMRegister src, uint8_t imm8);
void vextracti64x2(XMMRegister 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(XMMRegister dst, XMMRegister src, uint8_t imm8);
void vextracti64x4(Address dst, XMMRegister src, uint8_t imm8);
// vextractf forms // vextractf forms
void vextractf128(XMMRegister dst, XMMRegister src, uint8_t imm8); 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(XMMRegister dst, XMMRegister src, uint8_t imm8);
void vextractf64x4(Address 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 // xmm/mem sourced byte/word/dword/qword replicate
void evpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len); void vpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastb(XMMRegister dst, Address src, int vector_len); void vpbroadcastb(XMMRegister dst, Address src, int vector_len);
void evpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len); void vpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastw(XMMRegister dst, Address src, int vector_len); void vpbroadcastw(XMMRegister dst, Address src, int vector_len);
void evpbroadcastd(XMMRegister dst, XMMRegister src, int vector_len); void vpbroadcastd(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastd(XMMRegister dst, Address src, int vector_len); void vpbroadcastd(XMMRegister dst, Address src, int vector_len);
void evpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len); void vpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastq(XMMRegister dst, Address 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, XMMRegister src, int vector_len);
void evbroadcasti64x2(XMMRegister dst, Address src, int vector_len); void evbroadcasti64x2(XMMRegister dst, Address src, int vector_len);
// scalar single/double precision replicate // scalar single/double precision replicate
void evpbroadcastss(XMMRegister dst, XMMRegister src, int vector_len); void vpbroadcastss(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastss(XMMRegister dst, Address src, int vector_len); void vpbroadcastss(XMMRegister dst, Address src, int vector_len);
void evpbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len); void vpbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len);
void evpbroadcastsd(XMMRegister dst, Address src, int vector_len); void vpbroadcastsd(XMMRegister dst, Address src, int vector_len);
// gpr sourced byte/word/dword/qword replicate // gpr sourced byte/word/dword/qword replicate
void evpbroadcastb(XMMRegister dst, Register src, int vector_len); 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)); static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], (jlong)UCONST64(0x8000000000000000), (jlong)UCONST64(0x8000000000000000));
NEEDS_CLEANUP // remove this definitions ? NEEDS_CLEANUP // remove this definitions ?
const Register IC_Klass = rax; // where the IC klass is cached const Register IC_Klass = rax; // where the IC klass is cached
const Register SYNC_header = rax; // synchronization header 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: { case T_FLOAT: {
if (dest->is_single_xmm()) { 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()); __ xorps(dest->as_xmm_float_reg(), dest->as_xmm_float_reg());
} else { } else {
__ movflt(dest->as_xmm_float_reg(), __ 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: { case T_DOUBLE: {
if (dest->is_double_xmm()) { 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()); __ xorpd(dest->as_xmm_double_reg(), dest->as_xmm_double_reg());
} else { } else {
__ movdbl(dest->as_xmm_double_reg(), __ 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()) { if (value->is_double_xmm()) {
switch(code) { switch(code) {
case lir_abs : case lir_abs :
{ {
if (dest->as_xmm_double_reg() != value->as_xmm_double_reg()) { #ifdef _LP64
__ movdbl(dest->as_xmm_double_reg(), value->as_xmm_double_reg()); 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; 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()) { if (left->is_single_cpu()) {
__ negl(left->as_register()); __ negl(left->as_register());
move_regs(left->as_register(), dest->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 #endif // _LP64
} else if (dest->is_single_xmm()) { } else if (dest->is_single_xmm()) {
if (left->as_xmm_float_reg() != dest->as_xmm_float_reg()) { #ifdef _LP64
__ movflt(dest->as_xmm_float_reg(), left->as_xmm_float_reg()); 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) { else
__ vnegatess(dest->as_xmm_float_reg(), dest->as_xmm_float_reg(), #endif
ExternalAddress((address)float_signflip_pool)); {
} else { 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(), __ xorps(dest->as_xmm_float_reg(),
ExternalAddress((address)float_signflip_pool)); ExternalAddress((address)float_signflip_pool));
} }
} else if (dest->is_double_xmm()) { } else if (dest->is_double_xmm()) {
if (left->as_xmm_double_reg() != dest->as_xmm_double_reg()) { #ifdef _LP64
__ movdbl(dest->as_xmm_double_reg(), left->as_xmm_double_reg()); 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) { else
__ vnegatesd(dest->as_xmm_double_reg(), dest->as_xmm_double_reg(), #endif
ExternalAddress((address)double_signflip_pool)); {
} else { 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(), __ xorpd(dest->as_xmm_double_reg(),
ExternalAddress((address)double_signflip_pool)); ExternalAddress((address)double_signflip_pool));
} }

View File

@ -320,7 +320,21 @@ void LIRGenerator::do_NegateOp(NegateOp* x) {
value.set_destroys_register(); value.set_destroys_register();
value.load_item(); value.load_item();
LIR_Opr reg = rlock(x); 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)); 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_input = value.result();
LIR_Opr calc_result = rlock_result(x); 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()) { 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; case vmIntrinsics::_dsqrt: __ sqrt (calc_input, calc_result, LIR_OprFact::illegalOpr); break;
default: ShouldNotReachHere(); default: ShouldNotReachHere();
} }

View File

@ -119,7 +119,7 @@ define_pd_global(bool, ThreadLocalHandshakes, false);
product(bool, UseStoreImmI16, true, \ product(bool, UseStoreImmI16, true, \
"Use store immediate 16-bits value instruction on x86") \ "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") \ "Highest supported AVX instructions set on x86/x64") \
range(0, 99) \ 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. // from register xmm0. Otherwise, the value is stored from the FPU stack.
void store_double(Address dst); 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 // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
void push_fTOS(); 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, Address src, int vector_len) { Assembler::vpand(dst, nds, src, vector_len); }
void vpand(XMMRegister dst, XMMRegister nds, AddressLiteral src, int 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 vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void vpcmpeqw(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); void vpmovzxbw(XMMRegister dst, Address src, int vector_len);

View File

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

View File

@ -816,7 +816,10 @@ public:
static bool supports_avx512cd() { return (_features & CPU_AVX512CD) != 0; } static bool supports_avx512cd() { return (_features & CPU_AVX512CD) != 0; }
static bool supports_avx512bw() { return (_features & CPU_AVX512BW) != 0; } static bool supports_avx512bw() { return (_features & CPU_AVX512BW) != 0; }
static bool supports_avx512vl() { return (_features & CPU_AVX512VL) != 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_avx512novl() { return (supports_evex() && !supports_avx512vl()); }
static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); } static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); }
static bool supports_avx256only() { return (supports_avx2() && !supports_evex()); } 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); 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 // XMM Double register operands
operand regD() %{ operand regD() %{
predicate( UseSSE>=2 ); predicate( UseSSE>=2 );
@ -4110,6 +4119,15 @@ operand regD() %{
interface(REG_INTER); 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) // Vectors : note, we use legacy registers to avoid extra (unneeded in 32-bit VM)
// runtime code generation via reg_class_dynamic. // runtime code generation via reg_class_dynamic.
operand vecS() %{ operand vecS() %{
@ -4120,6 +4138,14 @@ operand vecS() %{
interface(REG_INTER); interface(REG_INTER);
%} %}
operand legVecS() %{
constraint(ALLOC_IN_RC(vectors_reg_legacy));
match(VecS);
format %{ %}
interface(REG_INTER);
%}
operand vecD() %{ operand vecD() %{
constraint(ALLOC_IN_RC(vectord_reg_legacy)); constraint(ALLOC_IN_RC(vectord_reg_legacy));
match(VecD); match(VecD);
@ -4128,6 +4154,14 @@ operand vecD() %{
interface(REG_INTER); interface(REG_INTER);
%} %}
operand legVecD() %{
constraint(ALLOC_IN_RC(vectord_reg_legacy));
match(VecD);
format %{ %}
interface(REG_INTER);
%}
operand vecX() %{ operand vecX() %{
constraint(ALLOC_IN_RC(vectorx_reg_legacy)); constraint(ALLOC_IN_RC(vectorx_reg_legacy));
match(VecX); match(VecX);
@ -4136,6 +4170,14 @@ operand vecX() %{
interface(REG_INTER); interface(REG_INTER);
%} %}
operand legVecX() %{
constraint(ALLOC_IN_RC(vectorx_reg_legacy));
match(VecX);
format %{ %}
interface(REG_INTER);
%}
operand vecY() %{ operand vecY() %{
constraint(ALLOC_IN_RC(vectory_reg_legacy)); constraint(ALLOC_IN_RC(vectory_reg_legacy));
match(VecY); match(VecY);
@ -4144,6 +4186,14 @@ operand vecY() %{
interface(REG_INTER); interface(REG_INTER);
%} %}
operand legVecY() %{
constraint(ALLOC_IN_RC(vectory_reg_legacy));
match(VecY);
format %{ %}
interface(REG_INTER);
%}
//----------Memory Operands---------------------------------------------------- //----------Memory Operands----------------------------------------------------
// Direct Memory Operand // Direct Memory Operand
operand direct(immP addr) %{ operand direct(immP addr) %{
@ -6515,6 +6565,26 @@ instruct storeD(memory mem, regD src) %{
ins_pipe( pipe_slow ); 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) // Store XMM register to memory (single-precision floating point)
// MOVSS instruction // MOVSS instruction
instruct storeF(memory mem, regF src) %{ instruct storeF(memory mem, regF src) %{
@ -6528,6 +6598,26 @@ instruct storeF(memory mem, regF src) %{
ins_pipe( pipe_slow ); 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 // Store Float
instruct storeFPR( memory mem, regFPR1 src) %{ instruct storeFPR( memory mem, regFPR1 src) %{
predicate(UseSSE==0); predicate(UseSSE==0);

View File

@ -3656,6 +3656,15 @@ operand regF() %{
interface(REG_INTER); interface(REG_INTER);
%} %}
// Float register operands
operand vlRegF() %{
constraint(ALLOC_IN_RC(float_reg_vl));
match(RegF);
format %{ %}
interface(REG_INTER);
%}
// Double register operands // Double register operands
operand regD() %{ operand regD() %{
constraint(ALLOC_IN_RC(double_reg)); constraint(ALLOC_IN_RC(double_reg));
@ -3665,9 +3674,27 @@ operand regD() %{
interface(REG_INTER); interface(REG_INTER);
%} %}
// Double register operands
operand vlRegD() %{
constraint(ALLOC_IN_RC(double_reg_vl));
match(RegD);
format %{ %}
interface(REG_INTER);
%}
// Vectors // Vectors
operand vecS() %{ 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); match(VecS);
format %{ %} format %{ %}
@ -3675,7 +3702,15 @@ operand vecS() %{
%} %}
operand vecD() %{ 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); match(VecD);
format %{ %} format %{ %}
@ -3683,7 +3718,15 @@ operand vecD() %{
%} %}
operand vecX() %{ 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); match(VecX);
format %{ %} format %{ %}
@ -3691,7 +3734,15 @@ operand vecX() %{
%} %}
operand vecY() %{ 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); match(VecY);
format %{ %} format %{ %}
@ -5287,6 +5338,26 @@ instruct loadF(regF dst, memory mem)
ins_pipe(pipe_slow); // XXX 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 // Load Double
instruct loadD_partial(regD dst, memory mem) instruct loadD_partial(regD dst, memory mem)
%{ %{
@ -5314,6 +5385,26 @@ instruct loadD(regD dst, memory mem)
ins_pipe(pipe_slow); // XXX 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 // Load Effective Address
instruct leaP8(rRegP dst, indOffset8 mem) 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, 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); predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); 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, 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); predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); 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, 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); predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); 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, 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); predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); 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. // fast search of substring with known size.
instruct string_indexof_conL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, 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)); predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); 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. // fast search of substring with known size.
instruct string_indexof_conU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, 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)); predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); 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. // fast search of substring with known size.
instruct string_indexof_conUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, 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)); predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); 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, 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)); predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); 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, 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)); predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); 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, 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)); predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL));
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); 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, 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); predicate(UseSSE42Intrinsics);
match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); 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 // fast string equals
instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result, 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)); 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); 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 // fast array equals
instruct array_equalsB(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, 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); predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL);
match(Set result (AryEq ary1 ary2)); 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, 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); predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
match(Set result (AryEq ary1 ary2)); 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, 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)); match(Set result (HasNegatives ary1 len));
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); 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 // 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) %{ rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{
match(Set result (StrCompressedCopy src (Binary dst len))); 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); 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 // fast byte[] to char[] inflation
instruct string_inflate(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_RegI len, 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))); match(Set dummy (StrInflatedCopy src (Binary dst len)));
effect(TEMP tmp1, TEMP tmp2, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); 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 // encode char[] to byte[] in ISO_8859_1
instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, 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) %{ rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{
match(Set result (EncodeISOArray src (Binary dst len))); 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); 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_pop: // input always valid, result and info always invalid
case lir_return: // 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_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_monaddr: // input and result always valid, info always invalid
case lir_null_check: // input and info always valid, result 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 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_rem:
case lir_sqrt: case lir_sqrt:
case lir_abs: case lir_abs:
case lir_neg:
case lir_logic_and: case lir_logic_and:
case lir_logic_or: case lir_logic_or:
case lir_logic_xor: case lir_logic_xor:
@ -1662,7 +1662,6 @@ const char * LIR_Op::name() const {
case lir_null_check: s = "null_check"; break; case lir_null_check: s = "null_check"; break;
case lir_return: s = "return"; break; case lir_return: s = "return"; break;
case lir_safepoint: s = "safepoint"; break; case lir_safepoint: s = "safepoint"; break;
case lir_neg: s = "neg"; break;
case lir_leal: s = "leal"; break; case lir_leal: s = "leal"; break;
case lir_branch: s = "branch"; break; case lir_branch: s = "branch"; break;
case lir_cond_float_branch: s = "flt_cond_br"; 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_div_strictfp: s = "div_strictfp"; break;
case lir_rem: s = "rem"; break; case lir_rem: s = "rem"; break;
case lir_abs: s = "abs"; break; case lir_abs: s = "abs"; break;
case lir_neg: s = "neg"; break;
case lir_sqrt: s = "sqrt"; break; case lir_sqrt: s = "sqrt"; break;
case lir_logic_and: s = "logic_and"; break; case lir_logic_and: s = "logic_and"; break;
case lir_logic_or: s = "logic_or"; break; case lir_logic_or: s = "logic_or"; break;

View File

@ -911,7 +911,6 @@ enum LIR_Code {
, lir_null_check , lir_null_check
, lir_return , lir_return
, lir_leal , lir_leal
, lir_neg
, lir_branch , lir_branch
, lir_cond_float_branch , lir_cond_float_branch
, lir_move , lir_move
@ -939,6 +938,7 @@ enum LIR_Code {
, lir_rem , lir_rem
, lir_sqrt , lir_sqrt
, lir_abs , lir_abs
, lir_neg
, lir_tan , lir_tan
, lir_log10 , lir_log10
, lir_logic_and , lir_logic_and
@ -2075,7 +2075,6 @@ class LIR_List: public CompilationResourceObj {
void branch_destination(Label* lbl) { append(new LIR_OpLabel(lbl)); } 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)); } 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 // 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); 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 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 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 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)); } 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()); pop(op->in_opr());
break; break;
case lir_neg:
negate(op->in_opr(), op->result_opr());
break;
case lir_leal: case lir_leal:
leal(op->in_opr(), op->result_opr(), op->patch_code(), op->info()); leal(op->in_opr(), op->result_opr(), op->patch_code(), op->info());
break; 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); intrinsic_op(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op);
break; break;
case lir_neg:
negate(op->in_opr1(), op->result_opr(), op->in_opr2());
break;
case lir_logic_and: case lir_logic_and:
case lir_logic_or: case lir_logic_or:
case lir_logic_xor: case lir_logic_xor:

View File

@ -239,7 +239,7 @@ class LIR_Assembler: public CompilationResourceObj {
void align_backward_branch_target(); void align_backward_branch_target();
void align_call(LIR_Code code); 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 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); 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. // if they are not already on the _klasses list.
free_deallocate_list_C_heap_structures(); 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. // after erroneous classes are released.
classes_do(InstanceKlass::notify_unload_class); classes_do(InstanceKlass::unload_class);
// Clean up global class iterator for compiler // Clean up global class iterator for compiler
static_klass_iterator.adjust_saved_class(this); static_klass_iterator.adjust_saved_class(this);

View File

@ -218,18 +218,6 @@ int DependencyContext::remove_all_dependents() {
return marked; 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 #ifndef PRODUCT
void DependencyContext::print_dependent_nmethods(bool verbose) { void DependencyContext::print_dependent_nmethods(bool verbose) {
int idx = 0; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -141,10 +141,6 @@ class DependencyContext : public StackObj {
void expunge_stale_entries(); 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 #ifndef PRODUCT
void print_dependent_nmethods(bool verbose); void print_dependent_nmethods(bool verbose);
bool is_dependent_nmethod(nmethod* nm); 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() { bool G1ParEvacuateFollowersClosure::offer_termination() {
EventGCPhaseParallel event;
G1ParScanThreadState* const pss = par_scan_state(); G1ParScanThreadState* const pss = par_scan_state();
start_term_time(); start_term_time();
const bool res = terminator()->offer_termination(); const bool res = terminator()->offer_termination();
end_term_time(); end_term_time();
event.commit(GCId::current(), pss->worker_id(), G1GCPhaseTimes::phase_name(G1GCPhaseTimes::Termination));
return res; return res;
} }
void G1ParEvacuateFollowersClosure::do_void() { void G1ParEvacuateFollowersClosure::do_void() {
EventGCPhaseParallel event;
G1ParScanThreadState* const pss = par_scan_state(); G1ParScanThreadState* const pss = par_scan_state();
pss->trim_queue(); pss->trim_queue();
event.commit(GCId::current(), pss->worker_id(), G1GCPhaseTimes::phase_name(G1GCPhaseTimes::ObjCopy));
do { do {
EventGCPhaseParallel event;
pss->steal_and_trim_queue(queues()); pss->steal_and_trim_queue(queues());
event.commit(GCId::current(), pss->worker_id(), G1GCPhaseTimes::phase_name(G1GCPhaseTimes::ObjCopy));
} while (!offer_termination()); } while (!offer_termination());
} }
@ -4050,6 +4056,7 @@ public:
break; break;
} }
EventGCPhaseParallel event;
double start_time = os::elapsedTime(); double start_time = os::elapsedTime();
end = MIN2(end, _num_work_items); end = MIN2(end, _num_work_items);
@ -4064,9 +4071,11 @@ public:
if (is_young) { if (is_young) {
young_time += time_taken; young_time += time_taken;
has_young_time = true; has_young_time = true;
event.commit(GCId::current(), worker_id, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::YoungFreeCSet));
} else { } else {
non_young_time += time_taken; non_young_time += time_taken;
has_non_young_time = true; has_non_young_time = true;
event.commit(GCId::current(), worker_id, G1GCPhaseTimes::phase_name(G1GCPhaseTimes::NonYoungFreeCSet));
} }
start_time = end_time; 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) : G1EvacPhaseWithTrimTimeTracker::G1EvacPhaseWithTrimTimeTracker(G1ParScanThreadState* pss, Tickspan& total_time, Tickspan& trim_time) :
_pss(pss), _pss(pss),
_start(Ticks::now()), _start(Ticks::now()),
@ -490,7 +532,7 @@ void G1EvacPhaseWithTrimTimeTracker::stop() {
} }
G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id) : 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) { if (_phase_times != NULL) {
_start_time = Ticks::now(); _start_time = Ticks::now();
} }
@ -499,6 +541,7 @@ G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times,
G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() { G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
if (_phase_times != NULL) { if (_phase_times != NULL) {
_phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds()); _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/referenceProcessorPhaseTimes.hpp"
#include "gc/shared/weakProcessorPhaseTimes.hpp" #include "gc/shared/weakProcessorPhaseTimes.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/logLevel.hpp" #include "logging/logLevel.hpp"
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
@ -190,6 +191,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads); G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads);
void note_gc_start(); void note_gc_start();
void print(); void print();
static const char* phase_name(GCParPhases phase);
// record the time a phase took in seconds // record the time a phase took in seconds
void record_time_secs(GCParPhases phase, uint worker_i, double secs); void record_time_secs(GCParPhases phase, uint worker_i, double secs);
@ -385,6 +387,7 @@ protected:
G1GCPhaseTimes::GCParPhases _phase; G1GCPhaseTimes::GCParPhases _phase;
G1GCPhaseTimes* _phase_times; G1GCPhaseTimes* _phase_times;
uint _worker_id; uint _worker_id;
EventGCPhaseParallel _event;
public: public:
G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id); G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id);
virtual ~G1GCParPhaseTimesTracker(); virtual ~G1GCParPhaseTimesTracker();

View File

@ -40,6 +40,7 @@
#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/suspendibleThreadSet.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/iterator.hpp" #include "memory/iterator.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/access.inline.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) { void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) {
EventGCPhaseParallel event;
uint const region_idx = r->hrm_index(); uint const region_idx = r->hrm_index();
if (_scan_state->claim_iter(region_idx)) { 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); 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) { void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) {
EventGCPhaseParallel event;
r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); 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) { bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) {

View File

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

View File

@ -76,14 +76,12 @@ public:
// This class wraps a node and a pointer type. // This class wraps a node and a pointer type.
class C2AccessValuePtr: public C2AccessValue { class C2AccessValuePtr: public C2AccessValue {
int _alias_idx;
public: public:
C2AccessValuePtr(Node* node, const TypePtr* type) : C2AccessValuePtr(Node* node, const TypePtr* type) :
C2AccessValue(node, reinterpret_cast<const Type*>(type)) {} C2AccessValue(node, reinterpret_cast<const Type*>(type)) {}
const TypePtr* type() const { return reinterpret_cast<const TypePtr*>(_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 // 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; 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_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; virtual Node* atomic_add_at_resolved(C2AtomicAccess& access, Node* new_val, const Type* val_type) const;
void pin_atomic_op(C2AtomicAccess& access) const;
public: public:
// This is the entry-point for the backend to perform accesses through the Access API. // 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" /> <Field type="string" name="name" label="Name" />
</Event> </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" <Event name="AllocationRequiringGC" category="Java Virtual Machine, GC, Detailed" label="Allocation Requiring GC" thread="true" stackTrace="true"
startTime="false"> startTime="false">
<Field type="uint" name="gcId" label="Pending GC Identifier" relation="GcId" /> <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 #endif
void InstanceKlass::notify_unload_class(InstanceKlass* ik) { void InstanceKlass::unload_class(InstanceKlass* ik) {
// Release dependencies.
ik->dependencies().remove_all_dependents();
// notify the debugger // notify the debugger
if (JvmtiExport::should_post_class_unload()) { if (JvmtiExport::should_post_class_unload()) {
JvmtiExport::post_class_unload(ik); JvmtiExport::post_class_unload(ik);
@ -2462,16 +2465,8 @@ void InstanceKlass::release_C_heap_structures() {
FreeHeap(jmeths); FreeHeap(jmeths);
} }
// Release dependencies. assert(_dep_context == DependencyContext::EMPTY,
// It is desirable to use DC::remove_all_dependents() here, but, unfortunately, "dependencies should already be cleaned");
// 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();
#if INCLUDE_JVMTI #if INCLUDE_JVMTI
// Deallocate breakpoint records // Deallocate breakpoint records

View File

@ -1180,7 +1180,7 @@ public:
bool on_stack() const { return _constants->on_stack(); } bool on_stack() const { return _constants->on_stack(); }
// callbacks for actions during class unloading // 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); static void release_C_heap_structures(InstanceKlass* ik);
// Naming // 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); Node *adr = basic_plus_adr(ex_node, ex_node, offset);
const TypeOopPtr* val_type = TypeOopPtr::make_from_klass(env()->String_klass()); 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)); add_exception_state(make_exception_state(ex_node));
return; return;
@ -1544,8 +1544,7 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
return st; return st;
} }
Node* GraphKit::access_store_at(Node* ctl, Node* GraphKit::access_store_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
Node* val, Node* val,
@ -1559,7 +1558,6 @@ Node* GraphKit::access_store_at(Node* ctl,
val = _gvn.makecon(TypePtr::NULL_PTR); val = _gvn.makecon(TypePtr::NULL_PTR);
} }
set_control(ctl);
if (stopped()) { if (stopped()) {
return top(); // Dead path ? 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* GraphKit::access_atomic_cmpxchg_val_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -1622,7 +1619,6 @@ Node* GraphKit::access_atomic_cmpxchg_val_at(Node* ctl,
const Type* value_type, const Type* value_type,
BasicType bt, BasicType bt,
DecoratorSet decorators) { DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type); C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS, C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS,
bt, obj, addr, alias_idx); 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* GraphKit::access_atomic_cmpxchg_bool_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -1643,7 +1638,6 @@ Node* GraphKit::access_atomic_cmpxchg_bool_at(Node* ctl,
const Type* value_type, const Type* value_type,
BasicType bt, BasicType bt,
DecoratorSet decorators) { DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type); C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS, C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS,
bt, obj, addr, alias_idx); 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* GraphKit::access_atomic_xchg_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -1663,7 +1656,6 @@ Node* GraphKit::access_atomic_xchg_at(Node* ctl,
const Type* value_type, const Type* value_type,
BasicType bt, BasicType bt,
DecoratorSet decorators) { DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type); C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS, C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS,
bt, obj, addr, alias_idx); 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* GraphKit::access_atomic_add_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -1683,7 +1674,6 @@ Node* GraphKit::access_atomic_add_at(Node* ctl,
const Type* value_type, const Type* value_type,
BasicType bt, BasicType bt,
DecoratorSet decorators) { DecoratorSet decorators) {
set_control(ctl);
C2AccessValuePtr addr(adr, adr_type); C2AccessValuePtr addr(adr, adr_type);
C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS, bt, obj, addr, alias_idx); C2AtomicAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS, bt, obj, addr, alias_idx);
if (access.is_raw()) { 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) { void GraphKit::access_clone(Node* src, Node* dst, Node* size, bool is_array) {
set_control(ctl);
return _barrier_set->clone(this, src, dst, size, 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); sync_kit(ideal);
} }
Node* GraphKit::load_String_length(Node* ctrl, Node* str) { Node* GraphKit::load_String_length(Node* str, bool set_ctrl) {
Node* len = load_array_length(load_String_value(ctrl, str)); Node* len = load_array_length(load_String_value(str, set_ctrl));
Node* coder = load_String_coder(ctrl, str); Node* coder = load_String_coder(str, set_ctrl);
// Divide length by 2 if coder is UTF16 // Divide length by 2 if coder is UTF16
return _gvn.transform(new RShiftINode(len, coder)); 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(); int value_offset = java_lang_String::value_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0); false, NULL, 0);
@ -3866,7 +3855,7 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) {
ciTypeArrayKlass::make(T_BYTE), true, 0); ciTypeArrayKlass::make(T_BYTE), true, 0);
Node* p = basic_plus_adr(str, str, value_offset); Node* p = basic_plus_adr(str, str, value_offset);
Node* load = access_load_at(str, p, value_field_type, value_type, T_OBJECT, 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. // String.value field is known to be @Stable.
if (UseImplicitStableValues) { if (UseImplicitStableValues) {
load = cast_array_to_stable(load, value_type); load = cast_array_to_stable(load, value_type);
@ -3874,7 +3863,7 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) {
return load; return load;
} }
Node* GraphKit::load_String_coder(Node* ctrl, Node* str) { Node* GraphKit::load_String_coder(Node* str, bool set_ctrl) {
if (!CompactStrings) { if (!CompactStrings) {
return intcon(java_lang_String::CODER_UTF16); return intcon(java_lang_String::CODER_UTF16);
} }
@ -3883,27 +3872,31 @@ Node* GraphKit::load_String_coder(Node* ctrl, Node* str) {
false, NULL, 0); false, NULL, 0);
const TypePtr* coder_field_type = string_type->add_offset(coder_offset); const TypePtr* coder_field_type = string_type->add_offset(coder_offset);
int coder_field_idx = C->get_alias_index(coder_field_type); 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(); int value_offset = java_lang_String::value_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0); false, NULL, 0);
const TypePtr* value_field_type = string_type->add_offset(value_offset); 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(); int coder_offset = java_lang_String::coder_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0); false, NULL, 0);
const TypePtr* coder_field_type = string_type->add_offset(coder_offset); 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), access_store_at(str, basic_plus_adr(str, coder_offset), coder_field_type,
value, T_BYTE, coder_field_idx, MemNode::unordered); value, TypeInt::BYTE, T_BYTE, IN_HEAP | MO_UNORDERED);
} }
// Capture src and dst memory state with a MergeMemNode // Capture src and dst memory state with a MergeMemNode

View File

@ -572,8 +572,7 @@ class GraphKit : public Phase {
// Perform decorated accesses // Perform decorated accesses
Node* access_store_at(Node* ctl, Node* access_store_at(Node* obj, // containing obj
Node* obj, // containing obj
Node* adr, // actual adress to store val at Node* adr, // actual adress to store val at
const TypePtr* adr_type, const TypePtr* adr_type,
Node* val, Node* val,
@ -593,8 +592,7 @@ class GraphKit : public Phase {
BasicType bt, BasicType bt,
DecoratorSet decorators); DecoratorSet decorators);
Node* access_atomic_cmpxchg_val_at(Node* ctl, Node* access_atomic_cmpxchg_val_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -604,8 +602,7 @@ class GraphKit : public Phase {
BasicType bt, BasicType bt,
DecoratorSet decorators); DecoratorSet decorators);
Node* access_atomic_cmpxchg_bool_at(Node* ctl, Node* access_atomic_cmpxchg_bool_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -615,8 +612,7 @@ class GraphKit : public Phase {
BasicType bt, BasicType bt,
DecoratorSet decorators); DecoratorSet decorators);
Node* access_atomic_xchg_at(Node* ctl, Node* access_atomic_xchg_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -625,8 +621,7 @@ class GraphKit : public Phase {
BasicType bt, BasicType bt,
DecoratorSet decorators); DecoratorSet decorators);
Node* access_atomic_add_at(Node* ctl, Node* access_atomic_add_at(Node* obj,
Node* obj,
Node* adr, Node* adr,
const TypePtr* adr_type, const TypePtr* adr_type,
int alias_idx, int alias_idx,
@ -635,7 +630,7 @@ class GraphKit : public Phase {
BasicType bt, BasicType bt,
DecoratorSet decorators); 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); Node* access_resolve(Node* n, DecoratorSet decorators);
@ -849,11 +844,11 @@ class GraphKit : public Phase {
bool deoptimize_on_exception = false); bool deoptimize_on_exception = false);
// java.lang.String helpers // java.lang.String helpers
Node* load_String_length(Node* ctrl, Node* str); Node* load_String_length(Node* str, bool set_ctrl);
Node* load_String_value(Node* ctrl, Node* str); Node* load_String_value(Node* str, bool set_ctrl);
Node* load_String_coder(Node* ctrl, Node* str); Node* load_String_coder(Node* str, bool set_ctrl);
void store_String_value(Node* ctrl, Node* str, Node* value); void store_String_value(Node* str, Node* value);
void store_String_coder(Node* ctrl, Node* str, Node* value); void store_String_coder(Node* str, Node* value);
Node* capture_memory(const TypePtr* src_type, const TypePtr* dst_type); Node* capture_memory(const TypePtr* src_type, const TypePtr* dst_type);
Node* compress_string(Node* src, const TypeAryPtr* src_type, Node* dst, Node* count); 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); 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::_notify:
case vmIntrinsics::_notifyAll: case vmIntrinsics::_notifyAll:
if (ObjectMonitor::Knob_InlineNotify) { return inline_notify(intrinsic_id());
return inline_notify(intrinsic_id());
}
return false;
case vmIntrinsics::_addExactI: return inline_math_addExactI(false /* add */); case vmIntrinsics::_addExactI: return inline_math_addExactI(false /* add */);
case vmIntrinsics::_addExactL: return inline_math_addExactL(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; return false;
} }
if (is_store) { if (is_store) {
(void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, access_store_at(value, adr, TypeAryPtr::BYTES, ch, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED);
false, false, true /* mismatched */);
} else { } else {
ch = make_load(control(), adr, TypeInt::CHAR, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, ch = access_load_at(value, adr, TypeAryPtr::BYTES, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD);
LoadNode::DependsOnlyOnTest, false, false, true /* mismatched */);
set_result(ch); set_result(ch);
} }
return true; return true;
@ -2515,7 +2510,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
val = ConvL2X(val); val = ConvL2X(val);
val = gvn().transform(new CastX2PNode(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; return true;
@ -2734,24 +2729,24 @@ bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadSt
Node* result = NULL; Node* result = NULL;
switch (kind) { switch (kind) {
case LS_cmp_exchange: { 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); oldval, newval, value_type, type, decorators);
break; break;
} }
case LS_cmp_swap_weak: case LS_cmp_swap_weak:
decorators |= C2_WEAK_CMPXCHG; decorators |= C2_WEAK_CMPXCHG;
case LS_cmp_swap: { 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); oldval, newval, value_type, type, decorators);
break; break;
} }
case LS_get_set: { 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); newval, value_type, type, decorators);
break; break;
} }
case LS_get_add: { 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); newval, value_type, type, decorators);
break; 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. // TODO: generate fields copies for small objects instead.
Node* size = _gvn.transform(obj_size); 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. // Do not let reads from the cloned object float above the arraycopy.
if (alloc != NULL) { 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); 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; 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) { if (is_field) {
// Remember we wrote a volatile 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); Node* elem = expand_multianewarray(array_klass_1, &lengths[1], ndimensions-1, nargs);
intptr_t offset = header + ((intptr_t)i << LogBytesPerHeapOop); intptr_t offset = header + ((intptr_t)i << LogBytesPerHeapOop);
Node* eaddr = basic_plus_adr(array, offset); 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; 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()); Node* adr_node = method_data_addressing(md, data, DataLayout::flags_offset());
const TypePtr* adr_type = _gvn.type(adr_node)->is_ptr(); 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))); 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----------------------------- //----------------------------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. // 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* 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); src_array = kit.access_resolve(src_array, ACCESS_READ);
IdealKit ideal(&kit, true, true); 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 // Non-constant source string
if (CompactStrings) { if (CompactStrings) {
// Emit runtime check for coder // 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)); { __ if_then(coder, BoolTest::eq, __ ConI(java_lang_String::CODER_LATIN1)); {
// Source is Latin1 // Source is Latin1
copy_latin1_string(kit, ideal, src_array, count, dst_array, dst_coder, start); 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 // replace the argument with the null checked version
arg = null_string; arg = null_string;
sc->set_argument(argi, arg); sc->set_argument(argi, arg);
count = kit.load_String_length(kit.control(), arg); count = kit.load_String_length(arg, true);
arg_coder = kit.load_String_coder(kit.control(), arg); arg_coder = kit.load_String_coder(arg, true);
} else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) {
// s = s != null ? s : "null"; // s = s != null ? s : "null";
// length = length + (s.count - s.offset); // 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 // replace the argument with the null checked version
arg = phi; arg = phi;
sc->set_argument(argi, arg); sc->set_argument(argi, arg);
count = kit.load_String_length(kit.control(), arg); count = kit.load_String_length(arg, true);
arg_coder = kit.load_String_coder(kit.control(), arg); arg_coder = kit.load_String_coder(arg, true);
} else { } else {
// A corresponding nullcheck will be connected during IGVN MemNode::Ideal_common_DU_postCCP // 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 // 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. // 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); count = kit.load_String_length(arg, false);
arg_coder = kit.load_String_coder(NULL, arg); arg_coder = kit.load_String_coder(arg, false);
} }
if (arg->is_Con()) { if (arg->is_Con()) {
// Constant string. Get constant coder and length. // Constant string. Get constant coder and length.
@ -1918,7 +1918,7 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
sc->mode(0) == StringConcat::StringNullCheckMode)) { sc->mode(0) == StringConcat::StringNullCheckMode)) {
// Handle the case when there is only a single String argument. // Handle the case when there is only a single String argument.
// In this case, we can just pull the value from the String itself. // 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 { } else {
// Allocate destination byte array according to coder // Allocate destination byte array according to coder
dst_array = allocate_byte_array(kit, NULL, __ LShiftI(length, 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 // Initialize the string
kit.store_String_value(kit.control(), result, dst_array); kit.store_String_value(result, dst_array);
kit.store_String_coder(kit.control(), result, coder); kit.store_String_coder(result, coder);
// The value field is final. Emit a barrier here to ensure that the effect // 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 // 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 ); 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 // 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 // most general case because negating 0x80000000 does nothing. Needed for
// the CmpF3/SubI/CmpI idiom. // 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() }, { "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },
{ "MustCallLoadClassInternal", JDK_Version::jdk(10), JDK_Version::jdk(11), JDK_Version::jdk(12) }, { "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) }, { "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 -------------- // -------------- Obsolete Flags - sorted by expired_in --------------
{ "CheckAssertionStatusDirectives",JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) }, { "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) }, { "EmitSync", JDK_Version::undefined(), JDK_Version::jdk(12), JDK_Version::jdk(13) },
{ "SyncVerbose", 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) }, { "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 #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS
{ "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() }, { "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 " \ "Use LWP-based instead of libthread-based synchronization " \
"(SPARC only)") \ "(SPARC only)") \
\ \
experimental(ccstr, SyncKnobs, NULL, \
"(Unstable) Various monitor synchronization tunables") \
\
product(intx, MonitorBound, 0, "Bound Monitor population") \ product(intx, MonitorBound, 0, "Bound Monitor population") \
range(0, max_jint) \ range(0, max_jint) \
\ \

View File

@ -101,39 +101,15 @@
// The knob* variables are effectively final. Once set they should // The knob* variables are effectively final. Once set they should
// never be modified hence. Consider using __read_mostly with GCC. // 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 - 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_Bonus = 100; // spin success bonus
static int Knob_BonusB = 100; // spin success bonus static int Knob_BonusB = 100; // spin success bonus
static int Knob_Penalty = 200; // spin failure penalty static int Knob_Penalty = 200; // spin failure penalty
static int Knob_Poverty = 1000; static int Knob_Poverty = 1000;
static int Knob_SpinAfterFutile = 1; // Spin after returning from park()
static int Knob_FixedSpin = 0; 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_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; static volatile int InitDone = 0;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -299,7 +275,7 @@ void ObjectMonitor::enter(TRAPS) {
// transitions. The following spin is strictly optional ... // transitions. The following spin is strictly optional ...
// Note that if we acquire the monitor from an initial spin // Note that if we acquire the monitor from an initial spin
// we forgo posting JVMTI events and firing DTRACE probes. // we forgo posting JVMTI events and firing DTRACE probes.
if (Knob_SpinEarly && TrySpin (Self) > 0) { if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant"); assert(_owner == Self, "invariant");
assert(_recursions == 0, "invariant"); assert(_recursions == 0, "invariant");
assert(((oop)(object()))->mark() == markOopDesc::encode(this), "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 // to the owner. This has subtle but beneficial affinity
// effects. // effects.
if (TrySpin (Self) > 0) { if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant"); assert(_owner == Self, "invariant");
assert(_succ != Self, "invariant"); assert(_succ != Self, "invariant");
assert(_Responsible != Self, "invariant"); assert(_Responsible != Self, "invariant");
@ -583,20 +559,14 @@ void ObjectMonitor::EnterI(TRAPS) {
// We can defer clearing _succ until after the spin completes // We can defer clearing _succ until after the spin completes
// TrySpin() must tolerate being called with _succ == Self. // TrySpin() must tolerate being called with _succ == Self.
// Try yet another round of adaptive spinning. // 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 can find that we were unpark()ed and redesignated _succ while
// we were spinning. That's harmless. If we iterate and call park(), // we were spinning. That's harmless. If we iterate and call park(),
// park() will consume the event and return immediately and we'll // park() will consume the event and return immediately and we'll
// just spin again. This pattern can repeat, leaving _succ to simply // just spin again. This pattern can repeat, leaving _succ to simply
// spin on a CPU. Enable Knob_ResetEvent to clear pending unparks(). // spin on a CPU.
// Alternately, we can sample fired() here, and if set, forgo spinning
// in the next iteration.
if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
Self->_ParkEvent->reset();
OrderAccess::fence();
}
if (_succ == Self) _succ = NULL; if (_succ == Self) _succ = NULL;
// Invariant: after clearing _succ a thread *must* retry _owner before parking. // 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 // contended slow-path from EnterI(). We use ReenterI() only for
// monitor reentry in wait(). // monitor reentry in wait().
// //
// In the future we should reconcile EnterI() and ReenterI(), adding // In the future we should reconcile EnterI() and ReenterI().
// Knob_Reset and Knob_SpinAfterFutile support and restructuring the
// loop accordingly.
void ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) { void ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) {
assert(Self != NULL, "invariant"); assert(Self != NULL, "invariant");
@ -929,181 +897,60 @@ void ObjectMonitor::exit(bool not_suspended, TRAPS) {
for (;;) { for (;;) {
assert(THREAD == _owner, "invariant"); assert(THREAD == _owner, "invariant");
if (Knob_ExitPolicy == 0) { // release semantics: prior loads and stores from within the critical section
// release semantics: prior loads and stores from within the critical section // must not float (reorder) past the following store that drops the lock.
// must not float (reorder) past the following store that drops the lock. // On SPARC that requires MEMBAR #loadstore|#storestore.
// On SPARC that requires MEMBAR #loadstore|#storestore. // But of course in TSO #loadstore|#storestore is not required.
// But of course in TSO #loadstore|#storestore is not required. OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock
// I'd like to write one of the following: OrderAccess::storeload(); // See if we need to wake a successor
// A. OrderAccess::release() ; _owner = NULL if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
// B. OrderAccess::loadstore(); OrderAccess::storestore(); _owner = NULL; return;
// Unfortunately OrderAccess::release() and OrderAccess::loadstore() both }
// store into a _dummy variable. That store is not needed, but can result // Other threads are blocked trying to acquire the lock.
// 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.
// Normally the exiting thread is responsible for ensuring succession, // Normally the exiting thread is responsible for ensuring succession,
// but if other successors are ready or other entering threads are spinning // but if other successors are ready or other entering threads are spinning
// then this thread can simply store NULL into _owner and exit without // then this thread can simply store NULL into _owner and exit without
// waking a successor. The existence of spinners or ready successors // waking a successor. The existence of spinners or ready successors
// guarantees proper succession (liveness). Responsibility passes to the // guarantees proper succession (liveness). Responsibility passes to the
// ready or running successors. The exiting thread delegates the duty. // ready or running successors. The exiting thread delegates the duty.
// More precisely, if a successor already exists this thread is absolved // More precisely, if a successor already exists this thread is absolved
// of the responsibility of waking (unparking) one. // of the responsibility of waking (unparking) one.
// //
// The _succ variable is critical to reducing futile wakeup frequency. // The _succ variable is critical to reducing futile wakeup frequency.
// _succ identifies the "heir presumptive" thread that has been made // _succ identifies the "heir presumptive" thread that has been made
// ready (unparked) but that has not yet run. We need only one such // ready (unparked) but that has not yet run. We need only one such
// successor thread to guarantee progress. // successor thread to guarantee progress.
// See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf // See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf
// section 3.3 "Futile Wakeup Throttling" for details. // section 3.3 "Futile Wakeup Throttling" for details.
// //
// Note that spinners in Enter() also set _succ non-null. // Note that spinners in Enter() also set _succ non-null.
// In the current implementation spinners opportunistically set // In the current implementation spinners opportunistically set
// _succ so that exiting threads might avoid waking a successor. // _succ so that exiting threads might avoid waking a successor.
// Another less appealing alternative would be for the exiting thread // 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 drop the lock and then spin briefly to see if a spinner managed
// to acquire the lock. If so, the exiting thread could exit // to acquire the lock. If so, the exiting thread could exit
// immediately without waking a successor, otherwise the exiting // immediately without waking a successor, otherwise the exiting
// thread would need to dequeue and wake a successor. // thread would need to dequeue and wake a successor.
// (Note that we'd need to make the post-drop spin short, but no // (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. // shorter than the worst-case round-trip cache-line migration time.
// The dropped lock needs to become visible to the spinner, and then // 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 acquisition of the lock by the spinner must become visible to
// the exiting thread). // the exiting thread).
// It appears that an heir-presumptive (successor) must be made ready. // It appears that an heir-presumptive (successor) must be made ready.
// Only the current lock owner can manipulate the EntryList or // Only the current lock owner can manipulate the EntryList or
// drain _cxq, so we need to reacquire the lock. If we fail // drain _cxq, so we need to reacquire the lock. If we fail
// to reacquire the lock the responsibility for ensuring succession // to reacquire the lock the responsibility for ensuring succession
// falls to the new owner. // falls to the new owner.
// //
if (!Atomic::replace_if_null(THREAD, &_owner)) { if (!Atomic::replace_if_null(THREAD, &_owner)) {
return; 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;
}
}
} }
guarantee(_owner == THREAD, "invariant"); guarantee(_owner == THREAD, "invariant");
ObjectWaiter * w = NULL; 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; w = _EntryList;
if (w != NULL) { 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 // TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
// we have faster access to the tail. // we have faster access to the tail.
if (QMode == 1) { _EntryList = w;
// QMode == 1 : drain cxq to EntryList, reversing order ObjectWaiter * q = NULL;
// We also reverse the order of the list. ObjectWaiter * p;
ObjectWaiter * s = NULL; for (p = w; p != NULL; p = p->_next) {
ObjectWaiter * t = w; guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
ObjectWaiter * u = NULL; p->TState = ObjectWaiter::TS_ENTER;
while (t != NULL) { p->_prev = q;
guarantee(t->TState == ObjectWaiter::TS_CXQ, "invariant"); q = p;
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;
}
} }
// In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL // 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 // ST Self->_suspend_equivalent = false
// MEMBAR // MEMBAR
// LD Self_>_suspend_flags // 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) { 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(); return jSelf->handle_special_suspend_equivalent_condition();
} }
@ -1255,7 +1068,7 @@ void ObjectMonitor::ExitEpilog(Thread * Self, ObjectWaiter * Wakee) {
// 2. ST _owner = NULL // 2. ST _owner = NULL
// 3. unpark(wakee) // 3. unpark(wakee)
_succ = Knob_SuccEnabled ? Wakee->_thread : NULL; _succ = Wakee->_thread;
ParkEvent * Trigger = Wakee->_event; ParkEvent * Trigger = Wakee->_event;
// Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again. // 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"); 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, static void post_monitor_wait_event(EventJavaMonitorWait* event,
ObjectMonitor* monitor, ObjectMonitor* monitor,
jlong notifier_tid, 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. // we might just dequeue a thread from the WaitSet and directly unpark() it.
void ObjectMonitor::INotify(Thread * Self) { void ObjectMonitor::INotify(Thread * Self) {
const int policy = Knob_MoveNotifyee;
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify"); Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify");
ObjectWaiter * iterator = DequeueWaiter(); ObjectWaiter * iterator = DequeueWaiter();
if (iterator != NULL) { if (iterator != NULL) {
@ -1611,9 +1416,9 @@ void ObjectMonitor::INotify(Thread * Self) {
// or head (policy == 0). // or head (policy == 0).
// b. push it onto the front of the _cxq (policy == 2). // b. push it onto the front of the _cxq (policy == 2).
// For now we use (b). // For now we use (b).
if (policy != 4) {
iterator->TState = ObjectWaiter::TS_ENTER; iterator->TState = ObjectWaiter::TS_ENTER;
}
iterator->_notified = 1; iterator->_notified = 1;
iterator->_notifier_tid = JFR_THREAD_ID(Self); iterator->_notifier_tid = JFR_THREAD_ID(Self);
@ -1624,67 +1429,19 @@ void ObjectMonitor::INotify(Thread * Self) {
assert(list != iterator, "invariant"); assert(list != iterator, "invariant");
} }
if (policy == 0) { // prepend to EntryList // prepend to cxq
if (list == NULL) { if (list == NULL) {
iterator->_next = iterator->_prev = NULL; iterator->_next = iterator->_prev = NULL;
_EntryList = iterator; _EntryList = iterator;
} else { } 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
iterator->TState = ObjectWaiter::TS_CXQ; iterator->TState = ObjectWaiter::TS_CXQ;
for (;;) { for (;;) {
ObjectWaiter * tail = _cxq; ObjectWaiter * front = _cxq;
if (tail == NULL) { iterator->_next = front;
iterator->_next = NULL; if (Atomic::cmpxchg(iterator, &_cxq, front) == front) {
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;
break; 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 // _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 // on _WaitSetLock so it's not profitable to reduce the length of the
// critical section. // critical section.
if (policy < 4) { iterator->wait_reenter_begin(this);
iterator->wait_reenter_begin(this);
}
} }
Thread::SpinRelease(&_WaitSetLock); Thread::SpinRelease(&_WaitSetLock);
} }
@ -1854,33 +1609,19 @@ int ObjectMonitor::TrySpin(Thread * Self) {
// hold the duration constant but vary the frequency. // hold the duration constant but vary the frequency.
ctr = _SpinDuration; ctr = _SpinDuration;
if (ctr < Knob_SpinBase) ctr = Knob_SpinBase;
if (ctr <= 0) return 0; if (ctr <= 0) return 0;
if (Knob_SuccRestrict && _succ != NULL) return 0; if (NotRunnable(Self, (Thread *) _owner)) {
if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
return 0; 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. // We're good to spin ... spin ingress.
// CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades // CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades
// when preparing to LD...CAS _owner, etc and the CAS is likely // when preparing to LD...CAS _owner, etc and the CAS is likely
// to succeed. // to succeed.
int hits = 0; if (_succ == NULL) {
int msk = 0; _succ = Self;
int caspty = Knob_CASPenalty; }
int oxpty = Knob_OXPenalty;
int sss = Knob_SpinSetSucc;
if (sss && _succ == NULL) _succ = Self;
Thread * prv = NULL; Thread * prv = NULL;
// There are three ways to exit the following loop: // There are three ways to exit the following loop:
@ -1903,32 +1644,7 @@ int ObjectMonitor::TrySpin(Thread * Self) {
if (SafepointMechanism::poll(Self)) { if (SafepointMechanism::poll(Self)) {
goto Abort; // abrupt spin egress goto Abort; // abrupt spin egress
} }
if (Knob_UsePause & 1) SpinPause(); 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;
} }
// Probe _owner with TATAS // Probe _owner with TATAS
@ -1947,10 +1663,9 @@ int ObjectMonitor::TrySpin(Thread * Self) {
if (ox == NULL) { if (ox == NULL) {
// The CAS succeeded -- this thread acquired ownership // The CAS succeeded -- this thread acquired ownership
// Take care of some bookkeeping to exit spin state. // Take care of some bookkeeping to exit spin state.
if (sss && _succ == Self) { if (_succ == Self) {
_succ = NULL; _succ = NULL;
} }
if (MaxSpin > 0) Adjust(&_Spinner, -1);
// Increase _SpinDuration : // Increase _SpinDuration :
// The spin was successful (profitable) so we tend toward // 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: // 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 with prejudice -- goto Abort;
// * exit spin without prejudice. // * exit spin without prejudice.
// * Since CAS is high-latency, retry again immediately. // * Since CAS is high-latency, retry again immediately.
prv = ox; prv = ox;
if (caspty == -2) break; goto Abort;
if (caspty == -1) goto Abort;
ctr -= caspty;
continue;
} }
// Did lock ownership change hands ? // Did lock ownership change hands ?
if (ox != prv && prv != NULL) { if (ox != prv && prv != NULL) {
if (oxpty == -2) break; goto Abort;
if (oxpty == -1) goto Abort;
ctr -= oxpty;
} }
prv = ox; prv = ox;
@ -1991,10 +1701,12 @@ int ObjectMonitor::TrySpin(Thread * Self) {
// The owner must be executing in order to drop the lock. // The owner must be executing in order to drop the lock.
// Spinning while the owner is OFFPROC is idiocy. // Spinning while the owner is OFFPROC is idiocy.
// Consider: ctr -= RunnablePenalty ; // Consider: ctr -= RunnablePenalty ;
if (Knob_OState && NotRunnable (Self, ox)) { if (NotRunnable(Self, ox)) {
goto Abort; goto Abort;
} }
if (sss && _succ == NULL) _succ = Self; if (_succ == NULL) {
_succ = Self;
}
} }
// Spin failed with prejudice -- reduce _SpinDuration. // Spin failed with prejudice -- reduce _SpinDuration.
@ -2012,8 +1724,7 @@ int ObjectMonitor::TrySpin(Thread * Self) {
} }
Abort: Abort:
if (MaxSpin >= 0) Adjust(&_Spinner, -1); if (_succ == Self) {
if (sss && _succ == Self) {
_succ = NULL; _succ = NULL;
// Invariant: after setting succ=null a contending thread // Invariant: after setting succ=null a contending thread
// must recheck-retry _owner before parking. This usually happens // 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() { void ObjectMonitor::DeferredInitialize() {
if (InitDone > 0) return; if (InitDone > 0) return;
if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) { if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) {
@ -2237,70 +1925,13 @@ void ObjectMonitor::DeferredInitialize() {
// One-shot global initialization ... // One-shot global initialization ...
// The initialization is idempotent, so we don't need locks. // The initialization is idempotent, so we don't need locks.
// In the future consider doing this via os::init_2(). // 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 = ""; if (!os::is_MP()) {
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 {
Knob_SpinLimit = 0; Knob_SpinLimit = 0;
Knob_SpinBase = 0;
Knob_PreSpin = 0; Knob_PreSpin = 0;
Knob_FixedSpin = -1; Knob_FixedSpin = -1;
} }
os::free(knobs);
OrderAccess::fence(); OrderAccess::fence();
InitDone = 1; InitDone = 1;
} }

View File

@ -195,11 +195,6 @@ class ObjectMonitor {
static PerfCounter * _sync_Deflations; static PerfCounter * _sync_Deflations;
static PerfLongVariable * _sync_MonExtant; 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; static int Knob_SpinLimit;
void* operator new (size_t size) throw(); void* operator new (size_t size) throw();

View File

@ -598,7 +598,8 @@ private:
public: public:
ParallelSPCleanupThreadClosure(DeflateMonitorCounters* counters) : 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) { void do_thread(Thread* thread) {
ObjectSynchronizer::deflate_thread_local_monitors(thread, _counters); ObjectSynchronizer::deflate_thread_local_monitors(thread, _counters);

View File

@ -28,15 +28,19 @@
#include "code/icBuffer.hpp" #include "code/icBuffer.hpp"
#include "code/nmethod.hpp" #include "code/nmethod.hpp"
#include "compiler/compileBroker.hpp" #include "compiler/compileBroker.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/workgroup.hpp"
#include "jfr/jfrEvents.hpp" #include "jfr/jfrEvents.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "logging/logStream.hpp" #include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp" #include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/compilationPolicy.hpp" #include "runtime/compilationPolicy.hpp"
#include "runtime/interfaceSupport.inline.hpp" #include "runtime/interfaceSupport.inline.hpp"
#include "runtime/handshake.hpp"
#include "runtime/mutexLocker.hpp" #include "runtime/mutexLocker.hpp"
#include "runtime/orderAccess.hpp" #include "runtime/orderAccess.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
@ -197,6 +201,38 @@ bool NMethodSweeper::wait_for_stack_scanning() {
return _current.end(); 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. * 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 * 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() { void NMethodSweeper::mark_active_nmethods() {
CodeBlobClosure* cl = prepare_mark_active_nmethods(); CodeBlobClosure* cl = prepare_mark_active_nmethods();
if (cl != NULL) { 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() { 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"); 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 // If we do not want to reclaim not-entrant or zombie methods there is no need
// to scan stacks // to scan stacks
if (!MethodFlushing) { if (!MethodFlushing) {
@ -231,24 +311,7 @@ CodeBlobClosure* NMethodSweeper::prepare_mark_active_nmethods() {
} }
} }
if (wait_for_stack_scanning()) { return &set_hotness_closure;
_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;
}
} }
/** /**
@ -258,8 +321,20 @@ CodeBlobClosure* NMethodSweeper::prepare_mark_active_nmethods() {
void NMethodSweeper::do_stack_scanning() { void NMethodSweeper::do_stack_scanning() {
assert(!CodeCache_lock->owned_by_self(), "just checking"); assert(!CodeCache_lock->owned_by_self(), "just checking");
if (wait_for_stack_scanning()) { if (wait_for_stack_scanning()) {
VM_MarkActiveNMethods op; if (ThreadLocalHandshakes) {
VMThread::execute(&op); 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; _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 void mark_active_nmethods(); // Invoked at the end of each safepoint
static CodeBlobClosure* prepare_mark_active_nmethods(); static CodeBlobClosure* prepare_mark_active_nmethods();
static CodeBlobClosure* prepare_reset_hotness_counters();
static void sweeper_loop(); static void sweeper_loop();
static void notify(int code_blob_type); // Possibly start the sweeper thread. static void notify(int code_blob_type); // Possibly start the sweeper thread.
static void force_sweep(); static void force_sweep();

View File

@ -1050,40 +1050,14 @@ static void InduceScavenge(Thread * Self, const char * Whence) {
// TODO: assert thread state is reasonable // TODO: assert thread state is reasonable
if (ForceMonitorScavenge == 0 && Atomic::xchg (1, &ForceMonitorScavenge) == 0) { 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 // Induce a 'null' safepoint to scavenge monitors
// Must VM_Operation instance be heap allocated as the op will be enqueue and posted // 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. // to the VMthread and have a lifespan longer than that of this activation record.
// The VMThread will delete the op when completed. // The VMThread will delete the op when completed.
VMThread::execute(new VM_ScavengeMonitors()); 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) { ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
// A large MAXPRIVATE value reduces both list lock contention // A large MAXPRIVATE value reduces both list lock contention
// and list coherency traffic, but also tends to increase the // and list coherency traffic, but also tends to increase the
@ -1110,9 +1084,6 @@ ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
m->FreeNext = Self->omInUseList; m->FreeNext = Self->omInUseList;
Self->omInUseList = m; Self->omInUseList = m;
Self->omInUseCount++; Self->omInUseCount++;
if (ObjectMonitor::Knob_VerifyInUse) {
verifyInUse(Self);
}
} else { } else {
m->FreeNext = NULL; m->FreeNext = NULL;
} }
@ -1250,9 +1221,6 @@ void ObjectSynchronizer::omRelease(Thread * Self, ObjectMonitor * m,
} }
extracted = true; extracted = true;
Self->omInUseCount--; Self->omInUseCount--;
if (ObjectMonitor::Knob_VerifyInUse) {
verifyInUse(Self);
}
break; break;
} }
} }
@ -1763,14 +1731,6 @@ void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* co
// Consider: audit gFreeList to ensure that gMonitorFreeCount and list agree. // 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 ForceMonitorScavenge = 0; // Reset
OM_PERFDATA_OP(Deflations, inc(counters->nScavenged)); OM_PERFDATA_OP(Deflations, inc(counters->nScavenged));
@ -1796,9 +1756,6 @@ void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMo
// Adjust counters // Adjust counters
counters->nInCirculation += thread->omInUseCount; counters->nInCirculation += thread->omInUseCount;
thread->omInUseCount -= deflated_count; thread->omInUseCount -= deflated_count;
if (ObjectMonitor::Knob_VerifyInUse) {
verifyInUse(thread);
}
counters->nScavenged += deflated_count; counters->nScavenged += deflated_count;
counters->nInuse += thread->omInUseCount; counters->nInuse += thread->omInUseCount;
@ -1827,15 +1784,6 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure {
ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {} ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {}
void do_monitor(ObjectMonitor* mid) { void do_monitor(ObjectMonitor* mid) {
if (mid->owner() == THREAD) { 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); (void)mid->complete_exit(CHECK);
} }
} }

View File

@ -105,7 +105,6 @@ class ObjectSynchronizer : AllStatic {
static void reenter (Handle obj, intptr_t recursion, TRAPS); static void reenter (Handle obj, intptr_t recursion, TRAPS);
// thread-specific and global objectMonitor free list accessors // thread-specific and global objectMonitor free list accessors
static void verifyInUse(Thread * Self);
static ObjectMonitor * omAlloc(Thread * Self); static ObjectMonitor * omAlloc(Thread * Self);
static void omRelease(Thread * Self, ObjectMonitor * m, static void omRelease(Thread * Self, ObjectMonitor * m,
bool FromPerThreadAlloc); 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 // between JNI-acquired and regular Java monitors. We can only see
// regular Java monitors here if monitor enter-exit matching is broken. // 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 // ensure_join() ignores IllegalThreadStateExceptions, and so does
// ObjectSynchronizer::release_monitors_owned_by_thread(). // 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 // Sanity check even though JNI DetachCurrentThread() would have
// returned JNI_ERR if there was a Java frame. JavaThread exit // returned JNI_ERR if there was a Java frame. JavaThread exit
// should be done executing Java code by the time we get here. // 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); 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; 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)" #define HOTSPOT_BUILD_COMPILER "MS VC++ 14.0 (VS2015)"
#elif _MSC_VER == 1912 #elif _MSC_VER == 1912
#define HOTSPOT_BUILD_COMPILER "MS VC++ 15.5 (VS2017)" #define HOTSPOT_BUILD_COMPILER "MS VC++ 15.5 (VS2017)"
#elif _MSC_VER == 1913
#define HOTSPOT_BUILD_COMPILER "MS VC++ 15.6 (VS2017)"
#else #else
#define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER)
#endif #endif

View File

@ -802,7 +802,13 @@ public final class DateTimeFormatterBuilder {
return store.getText(value, style); return store.getText(value, style);
} }
@Override @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); return store.getTextIterator(style);
} }
}; };

View File

@ -28,6 +28,7 @@ package java.util;
import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.util.ArraysSupport; import jdk.internal.util.ArraysSupport;
import java.io.Serializable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.function.BinaryOperator; import java.util.function.BinaryOperator;
@ -4288,21 +4289,41 @@ public class Arrays {
// Misc // Misc
/** /**
* Returns a fixed-size list backed by the specified array. (Changes to * Returns a fixed-size list backed by the specified array. Changes made to
* the returned list "write through" to the array.) This method acts * the array will be visible in the returned list, and changes made to the
* as bridge between array-based and collection-based APIs, in * list will be visible in the array. The returned list is
* combination with {@link Collection#toArray}. The returned list is * {@link Serializable} and implements {@link RandomAccess}.
* 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 * <p>This method also provides a convenient way to create a fixed-size
* list initialized to contain several elements: * list initialized to contain several elements:
* <pre> * <pre>{@code
* List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly"); * List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
* </pre> * }</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 <T> the class of the objects in the array
* @param a the array by which the list will be backed * @param a the array by which the list will be backed
* @return a list view of the specified array * @return a list view of the specified array
* @throws NullPointerException if the specified array is {@code null}
*/ */
@SafeVarargs @SafeVarargs
@SuppressWarnings("varargs") @SuppressWarnings("varargs")

View File

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

View File

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

View File

@ -30,43 +30,14 @@ import java.lang.reflect.Constructor;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.Security;
import sun.security.util.SecurityProperties;
public final class SocketExceptions { public final class SocketExceptions {
private SocketExceptions() {} private SocketExceptions() {}
/** private static final boolean enhancedExceptionText =
* Security or system property which specifies categories of SecurityProperties.includedInExceptions("hostInfo");
* (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;
}
});
}
/** /**
* Utility which takes an exception and returns either the same exception * 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 * and detail message enhanced with addressing information from the
* given InetSocketAddress. * given InetSocketAddress.
* *
* If the system/security property "jdk.net.enhanceExceptionText" is not * If the system/security property "jdk.includeInExceptions" is not
* set or is false, then the original exception is returned. * set or does not contain the category hostInfo,
* then the original exception is returned.
* *
* Only specific IOException subtypes are supported. * 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 # java.nio.channels package will contain enhanced exception
# message information # 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 property setting in this file can be overridden by a system property of
# the same name, with the same syntax and possible values. # 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 #ifndef SO_REUSEPORT
#ifdef __linux__ #ifdef __linux__
#define SO_REUSEPORT 15 #define SO_REUSEPORT 15
#elif __solaris__ #elif defined(__solaris__)
#define SO_REUSEPORT 0x100e #define SO_REUSEPORT 0x100e
#elif defined(AIX) || defined(MACOSX) #elif defined(AIX) || defined(MACOSX)
#define SO_REUSEPORT 0x0200 #define SO_REUSEPORT 0x0200

View File

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

View File

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

View File

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

View File

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

View File

@ -23,11 +23,17 @@
* questions. * 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 <Cocoa/Cocoa.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h> #import <JavaNativeFoundation/JavaNativeFoundation.h>
@interface PropertiesUtilities : NSObject JNIEXPORT @interface PropertiesUtilities : NSObject
+ (NSString *) javaSystemPropertyForKey:(NSString *)key withEnv:(JNIEnv *)env; + (NSString *) javaSystemPropertyForKey:(NSString *)key withEnv:(JNIEnv *)env;

View File

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

View File

@ -433,7 +433,9 @@ public class Flags {
SYSTEM_MODULE(Flags.SYSTEM_MODULE), SYSTEM_MODULE(Flags.SYSTEM_MODULE),
DEPRECATED_ANNOTATION(Flags.DEPRECATED_ANNOTATION), DEPRECATED_ANNOTATION(Flags.DEPRECATED_ANNOTATION),
DEPRECATED_REMOVAL(Flags.DEPRECATED_REMOVAL), 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) { Flag(long flag) {
this.value = flag; this.value = flag;

View File

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

View File

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

View File

@ -50,8 +50,9 @@ import java.nio.file.Files;
import java.nio.file.InvalidPathException; import java.nio.file.InvalidPathException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.security.AccessController; import java.security.CodeSigner;
import java.security.PrivilegedAction; import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -63,6 +64,8 @@ import java.util.Map;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.NestingKind; import javax.lang.model.element.NestingKind;
@ -182,7 +185,7 @@ public class Main {
public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException { public void run(String[] runtimeArgs, String[] args) throws Fault, InvocationTargetException {
Path file = getFile(args); Path file = getFile(args);
Context context = new Context(); Context context = new Context(file.toAbsolutePath());
String mainClassName = compile(file, getJavacOpts(runtimeArgs), context); String mainClassName = compile(file, getJavacOpts(runtimeArgs), context);
String[] appArgs = Arrays.copyOfRange(args, 1, args.length); 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. * Returns the path for the filename found in the first of an array of arguments.
* *
* @param args the array * @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 * @throws Fault if there is a problem determining the path, or if the file does not exist
*/ */
private Path getFile(String[] args) throws Fault { private Path getFile(String[] args) throws Fault {
@ -396,12 +399,10 @@ public class Main {
*/ */
private void execute(String mainClassName, String[] appArgs, Context context) private void execute(String mainClassName, String[] appArgs, Context context)
throws Fault, InvocationTargetException { throws Fault, InvocationTargetException {
System.setProperty("jdk.launcher.sourcefile", context.file.toString());
ClassLoader cl = context.getClassLoader(ClassLoader.getSystemClassLoader()); ClassLoader cl = context.getClassLoader(ClassLoader.getSystemClassLoader());
try { try {
Class<?> appClass = Class.forName(mainClassName, true, cl); Class<?> appClass = Class.forName(mainClassName, true, cl);
if (appClass.getClassLoader() != cl) {
throw new Fault(Errors.UnexpectedClass(mainClassName));
}
Method main = appClass.getDeclaredMethod("main", String[].class); Method main = appClass.getDeclaredMethod("main", String[].class);
int PUBLIC_STATIC = Modifier.PUBLIC | Modifier.STATIC; int PUBLIC_STATIC = Modifier.PUBLIC | Modifier.STATIC;
if ((main.getModifiers() & PUBLIC_STATIC) != PUBLIC_STATIC) { if ((main.getModifiers() & PUBLIC_STATIC) != PUBLIC_STATIC) {
@ -481,14 +482,19 @@ public class Main {
* a class loader. * a class loader.
*/ */
private static class Context { 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) { JavaFileManager getFileManager(StandardJavaFileManager delegate) {
return new MemoryFileManager(inMemoryClasses, delegate); return new MemoryFileManager(inMemoryClasses, delegate);
} }
ClassLoader getClassLoader(ClassLoader parent) { 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 * <p>The classloader inverts the standard parent-delegation model, giving preference
* {@code findClass} to find classes in the in-memory cache. * 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 { 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}. * {@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); 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 @Override
protected Class<?> findClass(String name) throws ClassNotFoundException { protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = map.get(name); byte[] bytes = sourceFileClasses.get(name);
if (bytes == null) { if (bytes == null) {
throw new ClassNotFoundException(name); throw new ClassNotFoundException(name);
} }
return defineClass(name, bytes, 0, bytes.length); return defineClass(name, bytes, 0, bytes.length, domain);
} }
@Override @Override
public URL findResource(String name) { public URL findResource(String name) {
String binaryName = toBinaryName(name); String binaryName = toBinaryName(name);
if (binaryName == null || map.get(binaryName) == null) { if (binaryName == null || sourceFileClasses.get(binaryName) == null) {
return null; return null;
} }
@ -628,7 +724,7 @@ public class Main {
if (!u.getProtocol().equalsIgnoreCase(PROTOCOL)) { if (!u.getProtocol().equalsIgnoreCase(PROTOCOL)) {
throw new IllegalArgumentException(u.toString()); 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), 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 @Override
public void process(OptionHelper helper, String option, String operand) throws InvalidValueException { public void process(OptionHelper helper, String option, String operand) throws InvalidValueException {
Source source = Source.lookup(operand); 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 @Override
public void process(OptionHelper helper, String option, String operand) throws InvalidValueException { public void process(OptionHelper helper, String option, String operand) throws InvalidValueException {
Target target = Target.lookup(operand); Target target = Target.lookup(operand);

View File

@ -108,10 +108,6 @@ launcher.err.main.not.void=\
launcher.err.cant.find.class=\ launcher.err.cant.find.class=\
can''t find class: {0} can''t find class: {0}
# 0: string
launcher.err.unexpected.class=\
class found on application class path: {0}
# 0: string # 0: string
launcher.err.cant.find.main.method=\ launcher.err.cant.find.main.method=\
can''t find main(String[]) method in class: {0} 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"); String platformString = compOpts.get("--release");
if (platformString != null) { if (platformString != null) {
if (compOpts.isSet("-source")) { if (compOpts.isSet(Option.SOURCE.primaryName)) {
usageError("main.release.bootclasspath.conflict", "-source"); usageError("main.release.bootclasspath.conflict", Option.SOURCE.primaryName);
} }
if (fileManagerOpts.containsKey(Option.BOOT_CLASS_PATH)) { if (fileManagerOpts.containsKey(Option.BOOT_CLASS_PATH)) {
usageError("main.release.bootclasspath.conflict", Option.BOOT_CLASS_PATH.getPrimaryName()); usageError("main.release.bootclasspath.conflict", Option.BOOT_CLASS_PATH.getPrimaryName());

View File

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

View File

@ -208,12 +208,6 @@ public class HtmlConfiguration extends BaseConfiguration {
*/ */
public HtmlVersion htmlVersion = null; 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 * Collected set of doclint options
*/ */
@ -840,13 +834,6 @@ public class HtmlConfiguration extends BaseConfiguration {
} }
return true; 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<>(); Set<Doclet.Option> oset = new TreeSet<>();

View File

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

View File

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

View File

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

View File

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

View File

@ -295,6 +295,11 @@ public abstract class BaseConfiguration {
// A list of pairs containing urls and package list // A list of pairs containing urls and package list
private final List<Pair<String, String>> linkOfflineList = new ArrayList<>(); 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; public boolean dumpOnError = false;
@ -740,6 +745,13 @@ public abstract class BaseConfiguration {
return true; 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<Doclet.Option> set = new TreeSet<>();
set.addAll(Arrays.asList(options)); set.addAll(Arrays.asList(options));

View File

@ -226,16 +226,15 @@ doclet.Enum_Constant=Enum Constant
doclet.Description=Description doclet.Description=Description
doclet.ConstantField=Constant Field doclet.ConstantField=Constant Field
doclet.Value=Value 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 #Documentation for Enums
doclet.enum_values_doc.fullbody=\ doclet.enum_values_doc.fullbody=\
Returns an array containing the constants of this enum type, in\n\ 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\ the order they are declared.
over the constants as follows:\n\
<pre>\n\
for ({0} c : {0}.values())\n\
&nbsp; System.out.println(c);\n\
</pre>
doclet.enum_values_doc.return=\ doclet.enum_values_doc.return=\
an array containing the constants of this enum type, in the order they are declared 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