OpenJDK / amber / amber
changeset 56479:fef30a42d788 string-tapas
Automatic merge with default
author | mcimadamore |
---|---|
date | Thu, 30 May 2019 19:51:24 +0200 |
parents | 8d863ceba950 ad4285992012 |
children | 61353bf4e96d |
files | src/hotspot/share/Xusage.txt src/hotspot/share/gc/shenandoah/shenandoahHeapLock.hpp src/java.base/share/classes/java/lang/String.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties test/fmw/gtest/CHANGES test/fmw/gtest/CONTRIBUTORS test/fmw/gtest/LICENSE test/fmw/gtest/README.md test/fmw/gtest/include/gtest/gtest-death-test.h test/fmw/gtest/include/gtest/gtest-message.h test/fmw/gtest/include/gtest/gtest-param-test.h test/fmw/gtest/include/gtest/gtest-param-test.h.pump test/fmw/gtest/include/gtest/gtest-printers.h test/fmw/gtest/include/gtest/gtest-spi.h test/fmw/gtest/include/gtest/gtest-test-part.h test/fmw/gtest/include/gtest/gtest-typed-test.h test/fmw/gtest/include/gtest/gtest.h test/fmw/gtest/include/gtest/gtest_pred_impl.h test/fmw/gtest/include/gtest/gtest_prod.h test/fmw/gtest/include/gtest/internal/custom/README.md test/fmw/gtest/include/gtest/internal/custom/gtest-port.h test/fmw/gtest/include/gtest/internal/custom/gtest-printers.h test/fmw/gtest/include/gtest/internal/custom/gtest.h test/fmw/gtest/include/gtest/internal/gtest-death-test-internal.h test/fmw/gtest/include/gtest/internal/gtest-filepath.h test/fmw/gtest/include/gtest/internal/gtest-internal.h test/fmw/gtest/include/gtest/internal/gtest-linked_ptr.h test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h.pump test/fmw/gtest/include/gtest/internal/gtest-param-util.h test/fmw/gtest/include/gtest/internal/gtest-port-arch.h test/fmw/gtest/include/gtest/internal/gtest-port.h test/fmw/gtest/include/gtest/internal/gtest-string.h test/fmw/gtest/include/gtest/internal/gtest-tuple.h test/fmw/gtest/include/gtest/internal/gtest-tuple.h.pump test/fmw/gtest/include/gtest/internal/gtest-type-util.h test/fmw/gtest/include/gtest/internal/gtest-type-util.h.pump test/fmw/gtest/src/gtest-all.cc test/fmw/gtest/src/gtest-death-test.cc test/fmw/gtest/src/gtest-filepath.cc test/fmw/gtest/src/gtest-internal-inl.h test/fmw/gtest/src/gtest-port.cc test/fmw/gtest/src/gtest-printers.cc test/fmw/gtest/src/gtest-test-part.cc test/fmw/gtest/src/gtest-typed-test.cc test/fmw/gtest/src/gtest.cc test/fmw/gtest/src/gtest_main.cc |
diffstat | 393 files changed, 65702 insertions(+), 38549 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Thu May 23 22:14:23 2019 +0200 +++ b/.hgtags Thu May 30 19:51:24 2019 +0200 @@ -560,3 +560,4 @@ 6ccc7cd7931e34129f6b7e04988fc9a63958dde0 jdk-13+20 f2f11d7f7f4e7128f8aba6ffa576cfa76fbf7d1a jdk-13+21 181986c5476468bc2dd4532af49599003ee8af37 jdk-13+22 +b034d2dee5fc93d42a81b65e58ce3f91e42586ff jdk-13+23
--- a/make/Docs.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/Docs.gmk Thu May 30 19:51:24 2019 +0200 @@ -586,6 +586,7 @@ CSS := $(GLOBAL_SPECS_DEFAULT_CSS_FILE), \ OPTIONS := -A $($m_$f_BOTTOM_FILE), \ EXTRA_DEPS := $($m_$f_BOTTOM_FILE), \ + POST_PROCESS := $(TOOL_FIXUPPANDOC), \ )) \ $(eval JDK_SPECS_TARGETS += $($($m_$f_NAME))) \ ) \ @@ -616,6 +617,7 @@ CSS := $(GLOBAL_SPECS_DEFAULT_CSS_FILE), \ REPLACEMENTS := @@VERSION_SHORT@@ => $(VERSION_SHORT), \ OPTIONS := -A $(SPECS_BOTTOM_FILE_1), \ + POST_PROCESS := $(TOOL_FIXUPPANDOC), \ EXTRA_DEPS := $(PANDOC_HTML_MANPAGE_FILTER) \ $(PANDOC_HTML_MANPAGE_FILTER_JAVASCRIPT) \ $(SPECS_BOTTOM_FILE_1), \
--- a/make/Main.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/Main.gmk Thu May 30 19:51:24 2019 +0200 @@ -869,7 +869,7 @@ JVM_DOCS_TARGETS ?= hotspot-$(JVM_VARIANT_MAIN)-gensrc # The gensrc steps for hotspot and jdk.jdi create html spec files. - docs-jdk-specs: $(JVM_DOCS_TARGETS) jdk.jdi-gensrc \ + docs-jdk-specs: buildtools-jdk $(JVM_DOCS_TARGETS) jdk.jdi-gensrc \ docs-jdk-index docs-zip: docs-jdk
--- a/make/RunTests.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/RunTests.gmk Thu May 30 19:51:24 2019 +0200 @@ -1199,7 +1199,7 @@ JCOV_REPORT_TITLE += Code filters: $(JCOV_FILTERS)<br> endif JCOV_REPORT_TITLE += Tests: $(TEST) - + jcov-gen-report: jcov-stop-grabber $(call LogWarn, Generating JCov report ...) $(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar RepGen -sourcepath \
--- a/make/RunTestsPrebuilt.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/RunTestsPrebuilt.gmk Thu May 30 19:51:24 2019 +0200 @@ -337,6 +337,10 @@ default: all run-test-prebuilt: + # Need to make sure the failure logs output dir exists since + # ExecuteWithLog is called in RunTests.gmk. The PrepareFailureLogs macro + # is unfortunately not available at this point. + $(call MakeDir, $(MAKESUPPORT_OUTPUTDIR)/failure-logs) @$(RM) -f $(MAKESUPPORT_OUTPUTDIR)/exit-with-error # The lazy initialization of the cache file in FindTests.gmk does not # always work with RunTests.gmk. To guarantee that the jtreg test groups
--- a/make/ToolsJdk.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/ToolsJdk.gmk Thu May 30 19:51:24 2019 +0200 @@ -117,6 +117,9 @@ TOOL_PUBLICSUFFIXLIST = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.publicsuffixlist.GeneratePublicSuffixList +TOOL_FIXUPPANDOC = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + build.tools.fixuppandoc.Main + ########################################################################################## # Executable javascript filter for man page generation using pandoc.
--- a/make/hotspot/gensrc/GenerateSources.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/hotspot/gensrc/GenerateSources.gmk Thu May 30 19:51:24 2019 +0200 @@ -46,15 +46,6 @@ # While technically the rules below are "gendata" which can be done in parallel # with native compilation, let's keep it here for simplicity. -# The Xusage.txt file needs to have platform specific path separator -$(eval $(call SetupTextFileProcessing, CREATE_XUSAGE, \ - SOURCE_FILES := $(TOPDIR)/src/hotspot/share/Xusage.txt, \ - OUTPUT_FILE := $(JVM_LIB_OUTPUTDIR)/Xusage.txt, \ - REPLACEMENTS := separated by ;> => separated by $(PATH_SEP)> ; , \ -)) - -TARGETS += $(CREATE_XUSAGE) - # Setup the hotspot launcher script for developer use $(eval $(call SetupTextFileProcessing, CREATE_HOTSPOT_LAUNCHER, \ SOURCE_FILES := $(TOPDIR)/make/hotspot/hotspot.script, \
--- a/make/hotspot/lib/CompileGtest.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/hotspot/lib/CompileGtest.gmk Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -64,11 +64,16 @@ EXCLUDES := $(JVM_EXCLUDES), \ EXCLUDE_FILES := gtestLauncher.cpp, \ EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \ - EXTRA_FILES := $(GTEST_FRAMEWORK_SRC)/src/gtest-all.cc, \ + EXTRA_FILES := \ + $(GTEST_FRAMEWORK_SRC)/googletest/src/gtest-all.cc \ + $(GTEST_FRAMEWORK_SRC)/googlemock/src/gmock-all.cc, \ EXTRA_OBJECT_FILES := $(filter-out %/operator_new$(OBJ_SUFFIX), \ $(BUILD_LIBJVM_ALL_OBJS)), \ - CFLAGS := $(JVM_CFLAGS) -I$(GTEST_FRAMEWORK_SRC) \ - -I$(GTEST_FRAMEWORK_SRC)/include \ + CFLAGS := $(JVM_CFLAGS) \ + -I$(GTEST_FRAMEWORK_SRC)/googletest \ + -I$(GTEST_FRAMEWORK_SRC)/googletest/include \ + -I$(GTEST_FRAMEWORK_SRC)/googlemock \ + -I$(GTEST_FRAMEWORK_SRC)/googlemock/include \ $(addprefix -I,$(GTEST_TEST_SRC)), \ CFLAGS_windows := -EHsc, \ CFLAGS_solaris := -DGTEST_HAS_EXCEPTIONS=0 -library=stlport4, \ @@ -90,7 +95,7 @@ ZIP_EXTERNAL_DEBUG_SYMBOLS := false, \ STRIP_SYMBOLS := false, \ PRECOMPILED_HEADER := $(JVM_PRECOMPILED_HEADER), \ - PRECOMPILED_HEADER_EXCLUDE := gtest-all.cc gtestMain.cpp, \ + PRECOMPILED_HEADER_EXCLUDE := gtest-all.cc gmock-all.cc gtestMain.cpp, \ DEFINE_THIS_FILE := false, \ )) @@ -105,8 +110,11 @@ OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \ EXTRA_FILES := $(GTEST_LAUNCHER_SRC), \ OBJECT_DIR := $(JVM_OUTPUTDIR)/gtest/launcher-objs, \ - CFLAGS := $(JVM_CFLAGS) -I$(GTEST_FRAMEWORK_SRC) \ - -I$(GTEST_FRAMEWORK_SRC)/include, \ + CFLAGS := $(JVM_CFLAGS) \ + -I$(GTEST_FRAMEWORK_SRC)/googletest \ + -I$(GTEST_FRAMEWORK_SRC)/googletest/include \ + -I$(GTEST_FRAMEWORK_SRC)/googlemock \ + -I$(GTEST_FRAMEWORK_SRC)/googlemock/include, \ LDFLAGS := $(LDFLAGS_JDKEXE), \ LDFLAGS_unix := -L$(JVM_OUTPUTDIR)/gtest $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_solaris := -library=stlport4, \
--- a/make/hotspot/lib/JvmDtraceObjects.gmk Thu May 23 22:14:23 2019 +0200 +++ b/make/hotspot/lib/JvmDtraceObjects.gmk Thu May 30 19:51:24 2019 +0200 @@ -51,7 +51,9 @@ hs_private.d \ ) - $(JVM_OUTPUTDIR)/objs/dtrace.d: $(DTRACE_SOURCE_FILES) + # *.d in the objs dir is used for generated make dependency files, so use + # *.dt for dtrace files to avoid clashes. + $(JVM_OUTPUTDIR)/objs/dtrace.dt: $(DTRACE_SOURCE_FILES) $(call LogInfo, Generating $(@F)) $(call MakeDir, $(@D)) $(CAT) $^ > $@ @@ -94,13 +96,13 @@ # Make sure we run our selected compiler for preprocessing instead of letting # the dtrace tool pick it on it's own. - $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.d $(DTRACE_INSTRUMENTED_OBJS) + $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.dt $(DTRACE_INSTRUMENTED_OBJS) $(call LogInfo, Generating $(@F) from $(<F) and object files) $(call MakeDir, $(DTRACE_SUPPORT_DIR)) - $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ - ($(CPP) $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)) + $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).dt, \ + ($(CPP) $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).dt)) $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \ - -s $(DTRACE_SUPPORT_DIR)/$(@F).d $(sort $(DTRACE_INSTRUMENTED_OBJS))) + -s $(DTRACE_SUPPORT_DIR)/$(@F).dt $(sort $(DTRACE_INSTRUMENTED_OBJS))) ############################################################################ # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so. @@ -126,11 +128,11 @@ $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H) $(call LogInfo, Running dtrace for $(<F)) $(call MakeDir, $(DTRACE_SUPPORT_DIR)) - $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \ + $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).dt, \ ($(CPP) $(DTRACE_CPP_FLAGS) -I$(DTRACE_GENSRC_DIR) $^ \ - > $(DTRACE_SUPPORT_DIR)/$(@F).d)) + > $(DTRACE_SUPPORT_DIR)/$(@F).dt)) $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \ - -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + -s $(DTRACE_SUPPORT_DIR)/$(@F).dt) ifeq ($(call isTargetCpuArch, sparc), true) $(call ExecuteWithLog, $@.elfedit, $(ELFEDIT) $(call GetElfeditCommands) $@) endif
--- a/make/scripts/compare.sh Thu May 23 22:14:23 2019 +0200 +++ b/make/scripts/compare.sh Thu May 30 19:51:24 2019 +0200 @@ -820,6 +820,9 @@ BIN_MSG="($BIN_MSG)" DIFF_BIN= fi + else + BIN_MSG= + DIFF_BIN= fi if [ -n "$STAT" ]; then @@ -1571,15 +1574,12 @@ fi if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then echo -n "Test " - # Test native libs are never stripped so will not compare well. - SKIP_BIN_DIFF="true" - ACCEPTED_SMALL_SIZE_DIFF_bak="$ACCEPTED_SMALL_SIZE_DIFF" - if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then - ACCEPTED_SMALL_SIZE_DIFF="true" + STRIP_ALL_bak="$STRIP_ALL" + if [ "$STRIP_TESTS_BEFORE_COMPARE" = "true" ]; then + STRIP_ALL="true" fi compare_all_libs $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test - SKIP_BIN_DIFF="false" - ACCEPTED_SMALL_SIZE_DIFF="$ACCEPTED_SMALL_SIZE_DIFF_bak" + STRIP_ALL="$STRIP_ALL_bak" fi if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_all_libs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir @@ -1593,10 +1593,12 @@ fi if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then echo -n "Test " - # Test native executables are never stripped so will not compare well. - SKIP_BIN_DIFF="true" + STRIP_ALL_bak="$STRIP_ALL" + if [ "$STRIP_TESTS_BEFORE_COMPARE" = "true" ]; then + STRIP_ALL="true" + fi compare_all_execs $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test - SKIP_BIN_DIFF="false" + STRIP_ALL="$STRIP_ALL_bak" fi if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then compare_all_execs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
--- a/make/scripts/compare_exceptions.sh.incl Thu May 23 22:14:23 2019 +0200 +++ b/make/scripts/compare_exceptions.sh.incl Thu May 30 19:51:24 2019 +0200 @@ -40,6 +40,9 @@ ./lib/server/libjvm.so ./hotspot/gtest/server/libjvm.so " + STRIP_BEFORE_COMPARE=" + ./hotspot/gtest/server/libjvm.so + " elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then SKIP_BIN_DIFF="true" SKIP_FULLDUMP_DIFF="true" @@ -56,6 +59,7 @@ ./lib/libfontmanager.so ./lib/libsaproc.so " + STRIP_TESTS_BEFORE_COMPARE="true" elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then SKIP_BIN_DIFF="true" SKIP_FULLDUMP_DIFF="true" @@ -72,4 +76,5 @@ ./lib/server/libjvm.dylib ./hotspot/gtest/server/libjvm.dylib " + STRIP_TESTS_BEFORE_COMPARE="true" fi
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Thu May 30 19:51:24 2019 +0200 @@ -1491,6 +1491,25 @@ INSN(eorw, 0, 0b10, 0); INSN(andsw, 0, 0b11, 0); +#undef INSN + +#define INSN(NAME, size, op, N) \ + void NAME(Register Rd, Register Rn, Register Rm, \ + enum shift_kind kind = LSL, unsigned shift = 0) { \ + starti; \ + f(N, 21); \ + zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); \ + op_shifted_reg(0b01010, kind, shift, size, op); \ + } \ + \ + /* These instructions have no immediate form. Provide an overload so \ + that if anyone does try to use an immediate operand -- this has \ + happened! -- we'll get a compile-time error. */ \ + void NAME(Register Rd, Register Rn, unsigned imm, \ + enum shift_kind kind = LSL, unsigned shift = 0) { \ + assert(false, " can't be used with immediate operand"); \ + } + INSN(bic, 1, 0b00, 1); INSN(orn, 1, 0b01, 1); INSN(eon, 1, 0b10, 1);
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp Thu May 30 19:51:24 2019 +0200 @@ -316,6 +316,9 @@ return start_offset; } +void LIR_Assembler::clinit_barrier(ciMethod* method) { + ShouldNotReachHere(); // not implemented +} void LIR_Assembler::jobject2reg(jobject o, Register reg) { if (o == NULL) { @@ -2268,7 +2271,7 @@ __ ldr(src, Address(sp, 4*BytesPerWord)); // r0 is -1^K where K == partial copied count - __ eonw(rscratch1, r0, 0); + __ eonw(rscratch1, r0, zr); // adjust length down and src/end pos up by partial copied count __ subw(length, length, rscratch1); __ addw(src_pos, src_pos, rscratch1);
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp Thu May 30 19:51:24 2019 +0200 @@ -211,18 +211,46 @@ __ bind(done); } -void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst) { +void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) { assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); Label is_null; __ cbz(dst, is_null); - resolve_forward_pointer_not_null(masm, dst); + resolve_forward_pointer_not_null(masm, dst, tmp); __ bind(is_null); } -// IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2. -void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst) { +// IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2, except those explicitely +// passed in. +void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) { assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); - __ ldr(dst, Address(dst, ShenandoahForwarding::byte_offset())); + // The below loads the mark word, checks if the lowest two bits are + // set, and if so, clear the lowest two bits and copy the result + // to dst. Otherwise it leaves dst alone. + // Implementing this is surprisingly awkward. I do it here by: + // - Inverting the mark word + // - Test lowest two bits == 0 + // - If so, set the lowest two bits + // - Invert the result back, and copy to dst + + bool borrow_reg = (tmp == noreg); + if (borrow_reg) { + // No free registers available. Make one useful. + tmp = rscratch1; + __ push(RegSet::of(tmp), sp); + } + + Label done; + __ ldr(tmp, Address(dst, oopDesc::mark_offset_in_bytes())); + __ eon(tmp, tmp, zr); + __ ands(zr, tmp, markOopDesc::lock_mask_in_place); + __ br(Assembler::NE, done); + __ orr(tmp, tmp, markOopDesc::marked_value); + __ eon(dst, tmp, zr); + __ bind(done); + + if (borrow_reg) { + __ pop(RegSet::of(tmp), sp); + } } void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Register tmp) { @@ -343,40 +371,6 @@ } -void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1, - Register t2, - Label& slow_case) { - - assert_different_registers(obj, t2); - assert_different_registers(obj, var_size_in_bytes); - Register end = t2; - - __ ldr(obj, Address(rthread, JavaThread::tlab_top_offset())); - if (var_size_in_bytes == noreg) { - __ lea(end, Address(obj, (int) (con_size_in_bytes + ShenandoahForwarding::byte_size()))); - } else { - __ add(var_size_in_bytes, var_size_in_bytes, ShenandoahForwarding::byte_size()); - __ lea(end, Address(obj, var_size_in_bytes)); - } - __ ldr(rscratch1, Address(rthread, JavaThread::tlab_end_offset())); - __ cmp(end, rscratch1); - __ br(Assembler::HI, slow_case); - - // update the tlab top pointer - __ str(end, Address(rthread, JavaThread::tlab_top_offset())); - - __ add(obj, obj, ShenandoahForwarding::byte_size()); - __ str(obj, Address(obj, ShenandoahForwarding::byte_offset())); - - // recover var_size_in_bytes if necessary - if (var_size_in_bytes == end) { - __ sub(var_size_in_bytes, var_size_in_bytes, obj); - } -} - void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val, bool acquire, bool release, bool weak, bool is_cae, Register result) { @@ -570,7 +564,7 @@ __ bind(work); __ mov(rscratch2, r0); - resolve_forward_pointer_not_null(cgen->assembler(), r0); + resolve_forward_pointer_not_null(cgen->assembler(), r0, rscratch1); __ cmp(rscratch2, r0); __ br(Assembler::NE, done);
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp Thu May 30 19:51:24 2019 +0200 @@ -54,8 +54,8 @@ bool tosca_live, bool expand_call); - void resolve_forward_pointer(MacroAssembler* masm, Register dst); - void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst); + void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); + void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); void load_reference_barrier(MacroAssembler* masm, Register dst, Register tmp); void load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Register tmp); @@ -80,13 +80,6 @@ Register dst, Address src, Register tmp1, Register tmp_thread); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); - virtual void tlab_allocate(MacroAssembler* masm, Register obj, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1, - Register t2, - Label& slow_case); - void cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val, bool acquire, bool release, bool weak, bool is_cae, Register result);
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Thu May 30 19:51:24 2019 +0200 @@ -129,8 +129,11 @@ int dcache_line = VM_Version::dcache_line_size(); + // Limit AllocatePrefetchDistance so that it does not exceed the + // constraint in AllocatePrefetchDistanceConstraintFunc. if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) - FLAG_SET_DEFAULT(AllocatePrefetchDistance, 3*dcache_line); + FLAG_SET_DEFAULT(AllocatePrefetchDistance, MIN2(512, 3*dcache_line)); + if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) FLAG_SET_DEFAULT(AllocatePrefetchStepSize, dcache_line); if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes))
--- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp Thu May 30 19:51:24 2019 +0200 @@ -191,6 +191,9 @@ return offset; } +void LIR_Assembler::clinit_barrier(ciMethod* method) { + ShouldNotReachHere(); // not implemented +} void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo* info) { jobject o = (jobject)Universe::non_oop_word();
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp Thu May 30 19:51:24 2019 +0200 @@ -79,6 +79,9 @@ return offset; } +void LIR_Assembler::clinit_barrier(ciMethod* method) { + ShouldNotReachHere(); // not implemented +} void LIR_Assembler::osr_entry() { // On-stack-replacement entry sequence:
--- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp Thu May 30 19:51:24 2019 +0200 @@ -81,6 +81,10 @@ return offset; } +void LIR_Assembler::clinit_barrier(ciMethod* method) { + ShouldNotReachHere(); // not implemented +} + void LIR_Assembler::osr_entry() { // On-stack-replacement entry sequence (interpreter frame layout described in interpreter_sparc.cpp): //
--- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp Thu May 30 19:51:24 2019 +0200 @@ -172,6 +172,9 @@ return offset; } +void LIR_Assembler::clinit_barrier(ciMethod* method) { + ShouldNotReachHere(); // not implemented +} void LIR_Assembler::osr_entry() { // On-stack-replacement entry sequence (interpreter frame layout described in interpreter_sparc.cpp):
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp Thu May 30 19:51:24 2019 +0200 @@ -359,6 +359,23 @@ return offset; } +void LIR_Assembler::clinit_barrier(ciMethod* method) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + assert(method->holder()->is_being_initialized() || method->holder()->is_initialized(), + "initialization should have been started"); + + Label L_skip_barrier; + Register klass = rscratch1; + Register thread = LP64_ONLY( r15_thread ) NOT_LP64( noreg ); + assert(thread != noreg, "x86_32 not implemented"); + + __ mov_metadata(klass, method->holder()->constant_encoding()); + __ clinit_barrier(klass, thread, &L_skip_barrier /*L_fast_path*/); + + __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + + __ bind(L_skip_barrier); +} void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo* info) { jobject o = NULL;
--- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp Thu May 30 19:51:24 2019 +0200 @@ -317,18 +317,46 @@ __ bind(done); } -void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst) { +void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) { assert(ShenandoahCASBarrier, "should be enabled"); Label is_null; __ testptr(dst, dst); __ jcc(Assembler::zero, is_null); - resolve_forward_pointer_not_null(masm, dst); + resolve_forward_pointer_not_null(masm, dst, tmp); __ bind(is_null); } -void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst) { +void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) { assert(ShenandoahCASBarrier || ShenandoahLoadRefBarrier, "should be enabled"); - __ movptr(dst, Address(dst, ShenandoahForwarding::byte_offset())); + // The below loads the mark word, checks if the lowest two bits are + // set, and if so, clear the lowest two bits and copy the result + // to dst. Otherwise it leaves dst alone. + // Implementing this is surprisingly awkward. I do it here by: + // - Inverting the mark word + // - Test lowest two bits == 0 + // - If so, set the lowest two bits + // - Invert the result back, and copy to dst + + bool borrow_reg = (tmp == noreg); + if (borrow_reg) { + // No free registers available. Make one useful. + tmp = rscratch1; + __ push(tmp); + } + + Label done; + __ movptr(tmp, Address(dst, oopDesc::mark_offset_in_bytes())); + __ notptr(tmp); + __ testb(tmp, markOopDesc::marked_value); + __ jccb(Assembler::notZero, done); + __ orptr(tmp, markOopDesc::marked_value); + __ notptr(tmp); + __ mov(dst, tmp); + __ bind(done); + + if (borrow_reg) { + __ pop(tmp); + } } @@ -338,13 +366,7 @@ Label done; Address gc_state(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); - __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL); - __ jccb(Assembler::zero, done); - - // Heap is unstable, need to perform the resolve even if LRB is inactive - resolve_forward_pointer_not_null(masm, dst); - - __ testb(gc_state, ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL); + __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED); __ jccb(Assembler::zero, done); if (dst != rax) { @@ -479,55 +501,6 @@ } } -void ShenandoahBarrierSetAssembler::tlab_allocate(MacroAssembler* masm, - Register thread, Register obj, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1, Register t2, - Label& slow_case) { - assert_different_registers(obj, t1, t2); - assert_different_registers(obj, var_size_in_bytes, t1); - Register end = t2; - if (!thread->is_valid()) { -#ifdef _LP64 - thread = r15_thread; -#else - assert(t1->is_valid(), "need temp reg"); - thread = t1; - __ get_thread(thread); -#endif - } - - __ verify_tlab(); - - __ movptr(obj, Address(thread, JavaThread::tlab_top_offset())); - if (var_size_in_bytes == noreg) { - __ lea(end, Address(obj, con_size_in_bytes + ShenandoahForwarding::byte_size())); - } else { - __ addptr(var_size_in_bytes, ShenandoahForwarding::byte_size()); - __ lea(end, Address(obj, var_size_in_bytes, Address::times_1)); - } - __ cmpptr(end, Address(thread, JavaThread::tlab_end_offset())); - __ jcc(Assembler::above, slow_case); - - // update the tlab top pointer - __ movptr(Address(thread, JavaThread::tlab_top_offset()), end); - - // Initialize brooks pointer -#ifdef _LP64 - __ incrementq(obj, ShenandoahForwarding::byte_size()); -#else - __ incrementl(obj, ShenandoahForwarding::byte_size()); -#endif - __ movptr(Address(obj, ShenandoahForwarding::byte_offset()), obj); - - // recover var_size_in_bytes if necessary - if (var_size_in_bytes == end) { - __ subptr(var_size_in_bytes, obj); - } - __ verify_tlab(); -} - // Special Shenandoah CAS implementation that handles false negatives // due to concurrent evacuation. #ifndef _LP64 @@ -856,7 +829,7 @@ address start = __ pc(); #ifdef _LP64 - Label not_done; + Label resolve_oop, slow_path; // We use RDI, which also serves as argument register for slow call. // RAX always holds the src object ptr, except after the slow call and @@ -878,13 +851,31 @@ // unlive: rdi __ testbool(r8); // unlive: r8 - __ jccb(Assembler::notZero, not_done); + __ jccb(Assembler::notZero, resolve_oop); __ pop(r8); __ pop(rdi); __ ret(0); - __ bind(not_done); + __ bind(resolve_oop); + + __ movptr(r8, Address(rax, oopDesc::mark_offset_in_bytes())); + // Test if both lowest bits are set. We trick it by negating the bits + // then test for both bits clear. + __ notptr(r8); + __ testb(r8, markOopDesc::marked_value); + __ jccb(Assembler::notZero, slow_path); + // Clear both lower bits. It's still inverted, so set them, and then invert back. + __ orptr(r8, markOopDesc::marked_value); + __ notptr(r8); + // At this point, r8 contains the decoded forwarding pointer. + __ mov(rax, r8); + + __ pop(r8); + __ pop(rdi); + __ ret(0); + + __ bind(slow_path); __ push(rcx); __ push(rdx);
--- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp Thu May 30 19:51:24 2019 +0200 @@ -55,8 +55,8 @@ bool tosca_live, bool expand_call); - void resolve_forward_pointer(MacroAssembler* masm, Register dst); - void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst); + void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); + void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); void load_reference_barrier_not_null(MacroAssembler* masm, Register dst); @@ -91,13 +91,6 @@ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); - virtual void tlab_allocate(MacroAssembler* masm, - Register thread, Register obj, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1, Register t2, - Label& slow_case); - virtual void barrier_stubs_init(); };
--- a/src/hotspot/cpu/x86/interp_masm_x86.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp Thu May 30 19:51:24 2019 +0200 @@ -487,7 +487,8 @@ Register tmp, int bcp_offset, size_t index_size) { - assert(cache != tmp, "must use different register"); + assert_different_registers(cache, tmp); + get_cache_index_at_bcp(tmp, bcp_offset, index_size); assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); // convert from field index to ConstantPoolCacheEntry index @@ -501,8 +502,9 @@ } // Load object from cpool->resolved_references(index) -void InterpreterMacroAssembler::load_resolved_reference_at_index( - Register result, Register index, Register tmp) { +void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, + Register index, + Register tmp) { assert_different_registers(result, index); get_constant_pool(result); @@ -516,14 +518,32 @@ } // load cpool->resolved_klass_at(index) -void InterpreterMacroAssembler::load_resolved_klass_at_index(Register cpool, - Register index, Register klass) { +void InterpreterMacroAssembler::load_resolved_klass_at_index(Register klass, + Register cpool, + Register index) { + assert_different_registers(cpool, index); + movw(index, Address(cpool, index, Address::times_ptr, sizeof(ConstantPool))); Register resolved_klasses = cpool; movptr(resolved_klasses, Address(cpool, ConstantPool::resolved_klasses_offset_in_bytes())); movptr(klass, Address(resolved_klasses, index, Address::times_ptr, Array<Klass*>::base_offset_in_bytes())); } +void InterpreterMacroAssembler::load_resolved_method_at_index(int byte_no, + Register method, + Register cache, + Register index) { + assert_different_registers(cache, index); + + const int method_offset = in_bytes( + ConstantPoolCache::base_offset() + + ((byte_no == TemplateTable::f2_byte) + ? ConstantPoolCacheEntry::f2_offset() + : ConstantPoolCacheEntry::f1_offset())); + + movptr(method, Address(cache, index, Address::times_ptr, method_offset)); // get f1 Method* +} + // Generate a subtype check: branch to ok_is_subtype if sub_klass is a // subtype of super_klass. //
--- a/src/hotspot/cpu/x86/interp_masm_x86.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp Thu May 30 19:51:24 2019 +0200 @@ -124,9 +124,14 @@ void load_resolved_reference_at_index(Register result, Register index, Register tmp = rscratch2); // load cpool->resolved_klass_at(index) - void load_resolved_klass_at_index(Register cpool, // the constant pool (corrupted on return) - Register index, // the constant pool index (corrupted on return) - Register klass); // contains the Klass on return + void load_resolved_klass_at_index(Register klass, // contains the Klass on return + Register cpool, // the constant pool (corrupted on return) + Register index); // the constant pool index (corrupted on return) + + void load_resolved_method_at_index(int byte_no, + Register method, + Register cache, + Register index); NOT_LP64(void f2ieee();) // truncate ftos to 32bits NOT_LP64(void d2ieee();) // truncate dtos to 64bits
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Thu May 30 19:51:24 2019 +0200 @@ -4603,6 +4603,29 @@ } +void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) { + assert(L_fast_path != NULL || L_slow_path != NULL, "at least one is required"); + + Label L_fallthrough; + if (L_fast_path == NULL) { + L_fast_path = &L_fallthrough; + } + + // Fast path check: class is fully initialized + cmpb(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); + jcc(Assembler::equal, *L_fast_path); + + // Fast path check: current thread is initializer thread + cmpptr(thread, Address(klass, InstanceKlass::init_thread_offset())); + if (L_slow_path != NULL) { + jcc(Assembler::notEqual, *L_slow_path); + } else { + jcc(Assembler::equal, *L_fast_path); + } + + bind(L_fallthrough); +} + void MacroAssembler::cmov32(Condition cc, Register dst, Address src) { if (VM_Version::supports_cmov()) { cmovl(cc, dst, src); @@ -5195,20 +5218,22 @@ void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) { // get mirror const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - movptr(mirror, Address(method, Method::const_offset())); - movptr(mirror, Address(mirror, ConstMethod::constants_offset())); - movptr(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes())); + load_method_holder(mirror, method); movptr(mirror, Address(mirror, mirror_offset)); resolve_oop_handle(mirror, tmp); } void MacroAssembler::load_method_holder_cld(Register rresult, Register rmethod) { - movptr(rresult, Address(rmethod, Method::const_offset())); - movptr(rresult, Address(rresult, ConstMethod::constants_offset())); - movptr(rresult, Address(rresult, ConstantPool::pool_holder_offset_in_bytes())); + load_method_holder(rresult, rmethod); movptr(rresult, Address(rresult, InstanceKlass::class_loader_data_offset())); } +void MacroAssembler::load_method_holder(Register holder, Register method) { + movptr(holder, Address(method, Method::const_offset())); // ConstMethod* + movptr(holder, Address(holder, ConstMethod::constants_offset())); // ConstantPool* + movptr(holder, Address(holder, ConstantPool::pool_holder_offset_in_bytes())); // InstanceKlass* +} + void MacroAssembler::load_klass(Register dst, Register src) { #ifdef _LP64 if (UseCompressedClassPointers) {
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp Thu May 30 19:51:24 2019 +0200 @@ -317,6 +317,8 @@ void load_mirror(Register mirror, Register method, Register tmp = rscratch2); void load_method_holder_cld(Register rresult, Register rmethod); + void load_method_holder(Register holder, Register method); + // oop manipulations void load_klass(Register dst, Register src); void store_klass(Register dst, Register src); @@ -581,6 +583,11 @@ Register temp_reg, Label& L_success); + void clinit_barrier(Register klass, + Register thread, + Label* L_fast_path = NULL, + Label* L_slow_path = NULL); + // method handles (JSR 292) Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Thu May 30 19:51:24 2019 +0200 @@ -974,6 +974,27 @@ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->c2i_entry_barrier(masm); + // Class initialization barrier for static methods + if (VM_Version::supports_fast_class_init_checks()) { + Label L_skip_barrier; + Register method = rbx; + + { // Bypass the barrier for non-static methods + Register flags = rscratch1; + __ movl(flags, Address(method, Method::access_flags_offset())); + __ testl(flags, JVM_ACC_STATIC); + __ jcc(Assembler::zero, L_skip_barrier); // non-static + } + + Register klass = rscratch1; + __ load_method_holder(klass, method); + __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); + + __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path + + __ bind(L_skip_barrier); + } + gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); __ flush(); @@ -2140,6 +2161,17 @@ int vep_offset = ((intptr_t)__ pc()) - start; + if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + Label L_skip_barrier; + Register klass = r10; + __ mov_metadata(klass, method->method_holder()); // InstanceKlass* + __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); + + __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path + + __ bind(L_skip_barrier); + } + #ifdef COMPILER1 // For Object.hashCode, System.identityHashCode try to pull hashCode from object header if available. if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) {
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp Thu May 30 19:51:24 2019 +0200 @@ -2719,12 +2719,13 @@ } void TemplateTable::resolve_cache_and_index(int byte_no, - Register Rcache, + Register cache, Register index, size_t index_size) { const Register temp = rbx; - assert_different_registers(Rcache, index, temp); - + assert_different_registers(cache, index, temp); + + Label L_clinit_barrier_slow; Label resolved; Bytecodes::Code code = bytecode(); @@ -2735,17 +2736,32 @@ } assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); - __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); + __ get_cache_and_index_and_bytecode_at_bcp(cache, index, temp, byte_no, 1, index_size); __ cmpl(temp, code); // have we resolved this bytecode? __ jcc(Assembler::equal, resolved); // resolve first time through + // Class initialization barrier slow path lands here as well. + __ bind(L_clinit_barrier_slow); address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); __ movl(temp, code); __ call_VM(noreg, entry, temp); // Update registers with resolved info - __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); + __ get_cache_and_index_at_bcp(cache, index, 1, index_size); + __ bind(resolved); + + // Class initialization barrier for static methods + if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { + const Register method = temp; + const Register klass = temp; + const Register thread = LP64_ONLY(r15_thread) NOT_LP64(noreg); + assert(thread != noreg, "x86_32 not supported"); + + __ load_resolved_method_at_index(byte_no, method, cache, index); + __ load_method_holder(klass, method); + __ clinit_barrier(klass, thread, NULL /*L_fast_path*/, &L_clinit_barrier_slow); + } } // The cache and index registers must be set before call @@ -2794,11 +2810,6 @@ assert_different_registers(itable_index, cache, index); // determine constant pool cache field offsets assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant"); - const int method_offset = in_bytes( - ConstantPoolCache::base_offset() + - ((byte_no == f2_byte) - ? ConstantPoolCacheEntry::f2_offset() - : ConstantPoolCacheEntry::f1_offset())); const int flags_offset = in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()); // access constant pool cache fields @@ -2807,7 +2818,7 @@ size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2)); resolve_cache_and_index(byte_no, cache, index, index_size); - __ movptr(method, Address(cache, index, Address::times_ptr, method_offset)); + __ load_resolved_method_at_index(byte_no, method, cache, index); if (itable_index != noreg) { // pick up itable or appendix index from f2 also: @@ -3862,9 +3873,7 @@ __ profile_virtual_call(rdx, rbcp, rlocals); // Get declaring interface class from method, and itable index - __ movptr(rax, Address(rbx, Method::const_offset())); - __ movptr(rax, Address(rax, ConstMethod::constants_offset())); - __ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes())); + __ load_method_holder(rax, rbx); __ movl(rbx, Address(rbx, Method::itable_index_offset())); __ subl(rbx, Method::itable_index_max); __ negl(rbx); @@ -4003,7 +4012,7 @@ __ jcc(Assembler::notEqual, slow_case_no_pop); // get InstanceKlass - __ load_resolved_klass_at_index(rcx, rdx, rcx); + __ load_resolved_klass_at_index(rcx, rcx, rdx); __ push(rcx); // save the contexts of klass for initializing the header // make sure klass is initialized & doesn't have finalizer @@ -4197,7 +4206,7 @@ // Get superklass in rax and subklass in rbx __ bind(quicked); __ mov(rdx, rax); // Save object in rdx; rax needed for subtype check - __ load_resolved_klass_at_index(rcx, rbx, rax); + __ load_resolved_klass_at_index(rax, rcx, rbx); __ bind(resolved); __ load_klass(rbx, rdx); @@ -4263,7 +4272,7 @@ // Get superklass in rax and subklass in rdx __ bind(quicked); __ load_klass(rdx, rax); - __ load_resolved_klass_at_index(rcx, rbx, rax); + __ load_resolved_klass_at_index(rax, rcx, rbx); __ bind(resolved);
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp Thu May 30 19:51:24 2019 +0200 @@ -936,6 +936,11 @@ // the intrinsic for java.lang.Thread.onSpinWait() static bool supports_on_spin_wait() { return supports_sse2(); } + // x86_64 supports fast class initialization checks for static methods. + static bool supports_fast_class_init_checks() { + return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32 + } + // support functions for virtualization detection private: static void check_virt_cpuid(uint32_t idx, uint32_t *regs);
--- a/src/hotspot/cpu/x86/x86.ad Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/x86.ad Thu May 30 19:51:24 2019 +0200 @@ -3153,30 +3153,6 @@ // ====================LEGACY REPLICATE======================================= -instruct Repl4B_mem(vecS dst, memory mem) %{ - predicate(n->as_Vector()->length() == 4 && UseAVX > 0 && !VM_Version::supports_avx512vlbw()); - match(Set dst (ReplicateB (LoadB mem))); - format %{ "punpcklbw $dst,$mem\n\t" - "pshuflw $dst,$dst,0x00\t! replicate4B" %} - ins_encode %{ - __ punpcklbw($dst$$XMMRegister, $mem$$Address); - __ pshuflw($dst$$XMMRegister, $dst$$XMMRegister, 0x00); - %} - ins_pipe( pipe_slow ); -%} - -instruct Repl8B_mem(vecD dst, memory mem) %{ - predicate(n->as_Vector()->length() == 8 && UseAVX > 0 && !VM_Version::supports_avx512vlbw()); - match(Set dst (ReplicateB (LoadB mem))); - format %{ "punpcklbw $dst,$mem\n\t" - "pshuflw $dst,$dst,0x00\t! replicate8B" %} - ins_encode %{ - __ punpcklbw($dst$$XMMRegister, $mem$$Address); - __ pshuflw($dst$$XMMRegister, $dst$$XMMRegister, 0x00); - %} - ins_pipe( pipe_slow ); -%} - instruct Repl16B(vecX dst, rRegI src) %{ predicate(n->as_Vector()->length() == 16 && !VM_Version::supports_avx512vlbw()); match(Set dst (ReplicateB src)); @@ -3193,20 +3169,6 @@ ins_pipe( pipe_slow ); %} -instruct Repl16B_mem(vecX dst, memory mem) %{ - predicate(n->as_Vector()->length() == 16 && UseAVX > 0 && !VM_Version::supports_avx512vlbw()); - match(Set dst (ReplicateB (LoadB mem))); - format %{ "punpcklbw $dst,$mem\n\t" - "pshuflw $dst,$dst,0x00\n\t" - "punpcklqdq $dst,$dst\t! replicate16B" %} - ins_encode %{ - __ punpcklbw($dst$$XMMRegister, $mem$$Address); - __ pshuflw($dst$$XMMRegister, $dst$$XMMRegister, 0x00); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - instruct Repl32B(vecY dst, rRegI src) %{ predicate(n->as_Vector()->length() == 32 && !VM_Version::supports_avx512vlbw()); match(Set dst (ReplicateB src)); @@ -3225,22 +3187,6 @@ ins_pipe( pipe_slow ); %} -instruct Repl32B_mem(vecY dst, memory mem) %{ - predicate(n->as_Vector()->length() == 32 && !VM_Version::supports_avx512vlbw()); - match(Set dst (ReplicateB (LoadB mem))); - format %{ "punpcklbw $dst,$mem\n\t" - "pshuflw $dst,$dst,0x00\n\t" - "punpcklqdq $dst,$dst\n\t" - "vinserti128_high $dst,$dst\t! replicate32B" %} - ins_encode %{ - __ punpcklbw($dst$$XMMRegister, $mem$$Address); - __ pshuflw($dst$$XMMRegister, $dst$$XMMRegister, 0x00); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - __ vinserti128_high($dst$$XMMRegister, $dst$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - instruct Repl64B(legVecZ dst, rRegI src) %{ predicate(n->as_Vector()->length() == 64 && !VM_Version::supports_avx512vlbw()); match(Set dst (ReplicateB src)); @@ -3261,24 +3207,6 @@ ins_pipe( pipe_slow ); %} -instruct Repl64B_mem(legVecZ dst, memory mem) %{ - predicate(n->as_Vector()->length() == 64 && !VM_Version::supports_avx512vlbw()); - match(Set dst (ReplicateB (LoadB mem))); - format %{ "punpcklbw $dst,$mem\n\t" - "pshuflw $dst,$dst,0x00\n\t" - "punpcklqdq $dst,$dst\n\t" - "vinserti128_high $dst,$dst\t" - "vinserti64x4 $dst,$dst,$dst,0x1\t! replicate64B" %} - ins_encode %{ - __ punpcklbw($dst$$XMMRegister, $mem$$Address); - __ pshuflw($dst$$XMMRegister, $dst$$XMMRegister, 0x00); - __ punpcklqdq($dst$$XMMRegister, $dst$$XMMRegister); - __ vinserti128_high($dst$$XMMRegister, $dst$$XMMRegister); - __ vinserti64x4($dst$$XMMRegister, $dst$$XMMRegister, $dst$$XMMRegister, 0x1); - %} - ins_pipe( pipe_slow ); -%} - instruct Repl16B_imm(vecX dst, immI con) %{ predicate(n->as_Vector()->length() == 16 && !VM_Version::supports_avx512vlbw()); match(Set dst (ReplicateB con));
--- a/src/hotspot/cpu/x86/x86_64.ad Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/cpu/x86/x86_64.ad Thu May 30 19:51:24 2019 +0200 @@ -874,6 +874,22 @@ int framesize = C->frame_size_in_bytes(); int bangsize = C->bang_size_in_bytes(); + if (C->clinit_barrier_on_entry()) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + assert(C->method()->holder()->is_being_initialized() || C->method()->holder()->is_initialized(), + "initialization should have been started"); + + Label L_skip_barrier; + Register klass = rscratch1; + + __ mov_metadata(klass, C->method()->holder()->constant_encoding()); + __ clinit_barrier(klass, r15_thread, &L_skip_barrier /*L_fast_path*/); + + __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path + + __ bind(L_skip_barrier); + } + __ verified_entry(framesize, C->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != NULL); C->set_frame_complete(cbuf.insts_size());
--- a/src/hotspot/os/aix/os_aix.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/os/aix/os_aix.cpp Thu May 30 19:51:24 2019 +0200 @@ -2442,6 +2442,7 @@ // // See http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/mprotect.htm + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+size), prot); bool rc = ::mprotect(addr, size, prot) == 0 ? true : false; if (!rc) { @@ -2482,6 +2483,7 @@ // A valid strategy is just to try again. This usually works. :-/ ::usleep(1000); + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+size), prot); if (::mprotect(addr, size, prot) == 0) { const bool read_protected_2 = (SafeFetch32((int*)addr, 0x12345678) == 0x12345678 &&
--- a/src/hotspot/os/bsd/os_bsd.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/os/bsd/os_bsd.cpp Thu May 30 19:51:24 2019 +0200 @@ -1933,6 +1933,7 @@ int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; #ifdef __OpenBSD__ // XXX: Work-around mmap/MAP_FIXED bug temporarily on OpenBSD + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+size), prot); if (::mprotect(addr, size, prot) == 0) { return true; } @@ -2017,6 +2018,7 @@ bool os::pd_uncommit_memory(char* addr, size_t size) { #ifdef __OpenBSD__ // XXX: Work-around mmap/MAP_FIXED bug temporarily on OpenBSD + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with PROT_NONE", p2i(addr), p2i(addr+size)); return ::mprotect(addr, size, PROT_NONE) == 0; #else uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE, @@ -2085,6 +2087,7 @@ assert(addr == bottom, "sanity check"); size = align_up(pointer_delta(addr, bottom, 1) + size, os::Bsd::page_size()); + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(bottom), p2i(bottom+size), prot); return ::mprotect(bottom, size, prot) == 0; }
--- a/src/hotspot/os/linux/os_linux.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/os/linux/os_linux.cpp Thu May 30 19:51:24 2019 +0200 @@ -3450,6 +3450,7 @@ assert(addr == bottom, "sanity check"); size = align_up(pointer_delta(addr, bottom, 1) + size, os::Linux::page_size()); + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(bottom), p2i(bottom+size), prot); return ::mprotect(bottom, size, prot) == 0; }
--- a/src/hotspot/os/solaris/os_solaris.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/os/solaris/os_solaris.cpp Thu May 30 19:51:24 2019 +0200 @@ -2666,6 +2666,7 @@ static bool solaris_mprotect(char* addr, size_t bytes, int prot) { assert(addr == (char*)align_down((uintptr_t)addr, os::vm_page_size()), "addr must be page aligned"); + Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+bytes), prot); int retVal = mprotect(addr, bytes, prot); return retVal == 0; } @@ -4229,6 +4230,7 @@ // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { + Events::log(NULL, "Protecting polling page " INTPTR_FORMAT " with PROT_NONE", p2i(_polling_page)); if (mprotect((char *)_polling_page, page_size, PROT_NONE) != 0) { fatal("Could not disable polling page"); } @@ -4236,6 +4238,7 @@ // Mark the polling page as readable void os::make_polling_page_readable(void) { + Events::log(NULL, "Protecting polling page " INTPTR_FORMAT " with PROT_READ", p2i(_polling_page)); if (mprotect((char *)_polling_page, page_size, PROT_READ) != 0) { fatal("Could not enable polling page"); }
--- a/src/hotspot/share/Xusage.txt Thu May 23 22:14:23 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ - -Xmixed mixed mode execution (default) - -Xint interpreted mode execution only - -Xbootclasspath:<directories and zip/jar files separated by ;> - set search path for bootstrap classes and resources - -Xbootclasspath/a:<directories and zip/jar files separated by ;> - append to end of bootstrap class path - -Xbootclasspath/p:<directories and zip/jar files separated by ;> - prepend in front of bootstrap class path - -Xnoclassgc disable class garbage collection - -Xlog:<opts> control JVM logging, use -Xlog:help for details - -Xbatch disable background compilation - -Xms<size> set initial Java heap size - -Xmx<size> set maximum Java heap size - -Xss<size> set java thread stack size - -Xfuture enable strictest checks, anticipating future default - (deprecated) - -Xrs reduce use of OS signals by Java/VM (see documentation) - -Xcheck:jni perform additional checks for JNI functions - -Xshare:off do not attempt to use shared class data - -Xshare:auto use shared class data if possible (default) - -Xshare:on require using shared class data, otherwise fail. - -The -X options are non-standard and subject to change without notice.
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp Thu May 30 19:51:24 2019 +0200 @@ -162,6 +162,9 @@ return !method->is_static(); } +bool LIR_Assembler::needs_clinit_barrier_on_entry(ciMethod* method) const { + return VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier(); +} int LIR_Assembler::code_offset() const { return _masm->offset(); @@ -621,6 +624,9 @@ } offsets()->set_value(CodeOffsets::Verified_Entry, _masm->offset()); _masm->verified_entry(); + if (needs_clinit_barrier_on_entry(compilation()->method())) { + clinit_barrier(compilation()->method()); + } build_frame(); offsets()->set_value(CodeOffsets::Frame_Complete, _masm->offset()); break;
--- a/src/hotspot/share/c1/c1_LIRAssembler.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp Thu May 30 19:51:24 2019 +0200 @@ -81,6 +81,9 @@ // returns offset of icache check int check_icache(); + bool needs_clinit_barrier_on_entry(ciMethod* method) const; + void clinit_barrier(ciMethod* method); + void jobject2reg(jobject o, Register reg); void jobject2reg_with_patching(Register reg, CodeEmitInfo* info);
--- a/src/hotspot/share/ci/ciMethod.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/ci/ciMethod.cpp Thu May 30 19:51:24 2019 +0200 @@ -933,6 +933,13 @@ return get_Method()->is_ignored_by_security_stack_walk(); } +// ------------------------------------------------------------------ +// ciMethod::needs_clinit_barrier +// +bool ciMethod::needs_clinit_barrier() const { + check_is_loaded(); + return is_static() && !holder()->is_initialized(); +} // ------------------------------------------------------------------ // invokedynamic support
--- a/src/hotspot/share/ci/ciMethod.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/ci/ciMethod.hpp Thu May 30 19:51:24 2019 +0200 @@ -245,6 +245,8 @@ ResourceBitMap live_local_oops_at_bci(int bci); + bool needs_clinit_barrier() const; + #ifdef COMPILER1 const BitMap& bci_block_start(); #endif
--- a/src/hotspot/share/ci/ciReplay.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/ci/ciReplay.cpp Thu May 30 19:51:24 2019 +0200 @@ -532,7 +532,11 @@ // old version w/o comp_level if (had_error() && (error_message() == comp_level_label)) { // use highest available tier - comp_level = TieredCompilation ? TieredStopAtLevel : CompLevel_highest_tier; + if (TieredCompilation) { + comp_level = TieredStopAtLevel; + } else { + comp_level = CompLevel_highest_tier; + } } if (!is_valid_comp_level(comp_level)) { return;
--- a/src/hotspot/share/code/nmethod.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/code/nmethod.cpp Thu May 30 19:51:24 2019 +0200 @@ -1261,7 +1261,7 @@ void nmethod::unlink_from_method() { if (method() != NULL) { - method()->unlink_code(); + method()->unlink_code(this); } }
--- a/src/hotspot/share/compiler/abstractDisassembler.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/compiler/abstractDisassembler.cpp Thu May 30 19:51:24 2019 +0200 @@ -213,7 +213,7 @@ st->print(" long"); } else { if (((uintptr_t)(here)&0x07) == 0) { - st->print("%23.1ld", *((jlong*)here)); + st->print(JLONG_FORMAT_W(23), *((jlong*)here)); } } st->fill_to(align += 3*tsize);
--- a/src/hotspot/share/compiler/disassembler.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/compiler/disassembler.cpp Thu May 30 19:51:24 2019 +0200 @@ -774,13 +774,14 @@ // Match "[lib]jvm[^/]*" in jvm_path. const char* base = buf; const char* p = strrchr(buf, *os::file_separator()); + if (p != NULL) lib_offset = p - base + 1; // this points to the first char after separator #ifdef _WIN32 p = strstr(p ? p : base, "jvm"); + if (p != NULL) jvm_offset = p - base; // this points to 'j' in jvm. #else p = strstr(p ? p : base, "libjvm"); + if (p != NULL) jvm_offset = p - base + 3; // this points to 'j' in libjvm. #endif - if (p != NULL) lib_offset = p - base + 1; - if (p != NULL) jvm_offset = p - base; } #endif @@ -794,11 +795,13 @@ // 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so strcpy(&buf[jvm_offset], hsdis_library_name); strcat(&buf[jvm_offset], os::dll_file_extension()); + if (Verbose) st->print_cr("Trying to load: %s", buf); _library = os::dll_load(buf, ebuf, sizeof ebuf); if (_library == NULL && lib_offset >= 0) { // 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so strcpy(&buf[lib_offset], hsdis_library_name); strcat(&buf[lib_offset], os::dll_file_extension()); + if (Verbose) st->print_cr("Trying to load: %s", buf); _library = os::dll_load(buf, ebuf, sizeof ebuf); } if (_library == NULL && lib_offset > 0) { @@ -809,6 +812,7 @@ lib_offset = p - buf + 1; strcpy(&buf[lib_offset], hsdis_library_name); strcat(&buf[lib_offset], os::dll_file_extension()); + if (Verbose) st->print_cr("Trying to load: %s", buf); _library = os::dll_load(buf, ebuf, sizeof ebuf); } } @@ -817,6 +821,7 @@ // 4. hsdis-<arch>.so (using LD_LIBRARY_PATH) strcpy(&buf[0], hsdis_library_name); strcat(&buf[0], os::dll_file_extension()); + if (Verbose) st->print_cr("Trying to load: %s via LD_LIBRARY_PATH or equivalent", buf); _library = os::dll_load(buf, ebuf, sizeof ebuf); }
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp Thu May 30 19:51:24 2019 +0200 @@ -295,7 +295,7 @@ call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry); } -bool ShenandoahBarrierSetC2::is_shenandoah_wb_call(Node* call) { +bool ShenandoahBarrierSetC2::is_shenandoah_lrb_call(Node* call) { return call->is_CallLeaf() && call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT); } @@ -472,7 +472,7 @@ return TypeFunc::make(domain, range); } -const TypeFunc* ShenandoahBarrierSetC2::shenandoah_write_barrier_Type() { +const TypeFunc* ShenandoahBarrierSetC2::shenandoah_load_reference_barrier_Type() { const Type **fields = TypeTuple::fields(1); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields); @@ -710,30 +710,6 @@ BarrierSetC2::clone(kit, src, dst, size, is_array); } -Node* ShenandoahBarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes, - Node*& i_o, Node*& needgc_ctrl, - Node*& fast_oop_ctrl, Node*& fast_oop_rawmem, - intx prefetch_lines) const { - PhaseIterGVN& igvn = macro->igvn(); - - // Allocate several words more for the Shenandoah brooks pointer. - size_in_bytes = new AddXNode(size_in_bytes, igvn.MakeConX(ShenandoahForwarding::byte_size())); - macro->transform_later(size_in_bytes); - - Node* fast_oop = BarrierSetC2::obj_allocate(macro, ctrl, mem, toobig_false, size_in_bytes, - i_o, needgc_ctrl, fast_oop_ctrl, fast_oop_rawmem, - prefetch_lines); - - // Bump up object for Shenandoah brooks pointer. - fast_oop = new AddPNode(macro->top(), fast_oop, igvn.MakeConX(ShenandoahForwarding::byte_size())); - macro->transform_later(fast_oop); - - // Initialize Shenandoah brooks pointer to point to the object itself. - fast_oop_rawmem = macro->make_store(fast_oop_ctrl, fast_oop_rawmem, fast_oop, ShenandoahForwarding::byte_offset(), fast_oop, T_OBJECT); - - return fast_oop; -} - // Support for GC barriers emitted during parsing bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const { if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true;
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp Thu May 30 19:51:24 2019 +0200 @@ -93,7 +93,7 @@ static ShenandoahBarrierSetC2* bsc2(); static bool is_shenandoah_wb_pre_call(Node* call); - static bool is_shenandoah_wb_call(Node* call); + static bool is_shenandoah_lrb_call(Node* call); static bool is_shenandoah_marking_if(PhaseTransform *phase, Node* n); static bool is_shenandoah_state_load(Node* n); static bool has_only_shenandoah_wb_pre_uses(Node* n); @@ -102,17 +102,12 @@ static const TypeFunc* write_ref_field_pre_entry_Type(); static const TypeFunc* shenandoah_clone_barrier_Type(); - static const TypeFunc* shenandoah_write_barrier_Type(); + static const TypeFunc* shenandoah_load_reference_barrier_Type(); virtual bool has_load_barriers() const { return true; } // This is the entry-point for the backend to perform accesses through the Access API. virtual void clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const; - virtual Node* obj_allocate(PhaseMacroExpand* macro, Node* ctrl, Node* mem, Node* toobig_false, Node* size_in_bytes, - Node*& i_o, Node*& needgc_ctrl, - Node*& fast_oop_ctrl, Node*& fast_oop_rawmem, - intx prefetch_lines) const; - // These are general helper methods used by C2 virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, ArrayCopyPhase phase) const; virtual void clone_barrier_at_expansion(ArrayCopyNode* ac, Node* call, PhaseIterGVN& igvn) const;
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Thu May 30 19:51:24 2019 +0200 @@ -1093,7 +1093,7 @@ mm->set_memory_at(Compile::AliasIdxRaw, raw_mem); phase->register_new_node(mm, ctrl); - Node* call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_write_barrier_Type(), CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT), "shenandoah_write_barrier", TypeRawPtr::BOTTOM); + Node* call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_load_reference_barrier_Type(), CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT), "shenandoah_load_reference_barrier", TypeRawPtr::BOTTOM); call->init_req(TypeFunc::Control, ctrl); call->init_req(TypeFunc::I_O, phase->C->top()); call->init_req(TypeFunc::Memory, mm); @@ -1191,12 +1191,6 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { ShenandoahBarrierSetC2State* state = ShenandoahBarrierSetC2::bsc2()->state(); - // Collect raw memory state at CFG points in the entire graph and - // record it in memory_nodes. Optimize the raw memory graph in the - // process. Optimizing the memory graph also makes the memory graph - // simpler. - GrowableArray<MemoryGraphFixer*> memory_graph_fixers; - Unique_Node_List uses; for (int i = 0; i < state->enqueue_barriers_count(); i++) { Node* barrier = state->enqueue_barrier(i); @@ -1412,6 +1406,22 @@ } } + for (int i = 0; i < state->load_reference_barriers_count(); i++) { + ShenandoahLoadReferenceBarrierNode* lrb = state->load_reference_barrier(i); + if (lrb->get_barrier_strength() == ShenandoahLoadReferenceBarrierNode::NONE) { + continue; + } + Node* ctrl = phase->get_ctrl(lrb); + IdealLoopTree* loop = phase->get_loop(ctrl); + if (loop->_head->is_OuterStripMinedLoop()) { + // Expanding a barrier here will break loop strip mining + // verification. Transform the loop so the loop nest doesn't + // appear as strip mined. + OuterStripMinedLoopNode* outer = loop->_head->as_OuterStripMinedLoop(); + hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase); + } + } + // Expand load-reference-barriers MemoryGraphFixer fixer(Compile::AliasIdxRaw, true, phase); Unique_Node_List uses_to_ignore; @@ -1431,7 +1441,6 @@ Node* raw_mem = fixer.find_mem(ctrl, lrb); Node* init_raw_mem = raw_mem; Node* raw_mem_for_ctrl = fixer.find_mem(ctrl, NULL); - // int alias = phase->C->get_alias_index(lrb->adr_type()); IdealLoopTree *loop = phase->get_loop(ctrl); CallStaticJavaNode* unc = lrb->pin_and_expand_null_check(phase->igvn()); @@ -1455,7 +1464,7 @@ assert(val->bottom_type()->make_oopptr(), "need oop"); assert(val->bottom_type()->make_oopptr()->const_oop() == NULL, "expect non-constant"); - enum { _heap_stable = 1, _not_cset, _not_equal, _evac_path, _null_path, PATH_LIMIT }; + enum { _heap_stable = 1, _not_cset, _fwded, _evac_path, _null_path, PATH_LIMIT }; Node* region = new RegionNode(PATH_LIMIT); Node* val_phi = new PhiNode(region, uncasted_val->bottom_type()->is_oopptr()); Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); @@ -1505,36 +1514,48 @@ IfNode* iff = unc_ctrl->in(0)->as_If(); phase->igvn().replace_input_of(iff, 1, phase->igvn().intcon(1)); } - Node* addr = new AddPNode(new_val, uncasted_val, phase->igvn().MakeConX(ShenandoahForwarding::byte_offset())); + Node* addr = new AddPNode(new_val, uncasted_val, phase->igvn().MakeConX(oopDesc::mark_offset_in_bytes())); phase->register_new_node(addr, ctrl); - assert(val->bottom_type()->isa_oopptr(), "what else?"); - const TypePtr* obj_type = val->bottom_type()->is_oopptr(); - const TypePtr* adr_type = TypeRawPtr::BOTTOM; - Node* fwd = new LoadPNode(ctrl, raw_mem, addr, adr_type, obj_type, MemNode::unordered); - phase->register_new_node(fwd, ctrl); + assert(new_val->bottom_type()->isa_oopptr(), "what else?"); + Node* markword = new LoadXNode(ctrl, raw_mem, addr, TypeRawPtr::BOTTOM, TypeX_X, MemNode::unordered); + phase->register_new_node(markword, ctrl); + + // Test if object is forwarded. This is the case if lowest two bits are set. + Node* masked = new AndXNode(markword, phase->igvn().MakeConX(markOopDesc::lock_mask_in_place)); + phase->register_new_node(masked, ctrl); + Node* cmp = new CmpXNode(masked, phase->igvn().MakeConX(markOopDesc::marked_value)); + phase->register_new_node(cmp, ctrl); // Only branch to LRB stub if object is not forwarded; otherwise reply with fwd ptr - Node* cmp = new CmpPNode(fwd, new_val); - phase->register_new_node(cmp, ctrl); - Node* bol = new BoolNode(cmp, BoolTest::eq); + Node* bol = new BoolNode(cmp, BoolTest::eq); // Equals 3 means it's forwarded phase->register_new_node(bol, ctrl); - IfNode* iff = new IfNode(ctrl, bol, PROB_UNLIKELY(0.999), COUNT_UNKNOWN); - if (reg2_ctrl == NULL) reg2_ctrl = iff; + IfNode* iff = new IfNode(ctrl, bol, PROB_LIKELY(0.999), COUNT_UNKNOWN); phase->register_control(iff, loop, ctrl); - Node* if_not_eq = new IfFalseNode(iff); - phase->register_control(if_not_eq, loop, iff); - Node* if_eq = new IfTrueNode(iff); - phase->register_control(if_eq, loop, iff); + Node* if_fwd = new IfTrueNode(iff); + phase->register_control(if_fwd, loop, iff); + Node* if_not_fwd = new IfFalseNode(iff); + phase->register_control(if_not_fwd, loop, iff); + + // Decode forward pointer: since we already have the lowest bits, we can just subtract them + // from the mark word without the need for large immediate mask. + Node* masked2 = new SubXNode(markword, masked); + phase->register_new_node(masked2, if_fwd); + Node* fwdraw = new CastX2PNode(masked2); + fwdraw->init_req(0, if_fwd); + phase->register_new_node(fwdraw, if_fwd); + Node* fwd = new CheckCastPPNode(NULL, fwdraw, val->bottom_type()); + phase->register_new_node(fwd, if_fwd); // Wire up not-equal-path in slots 3. - region->init_req(_not_equal, if_not_eq); - val_phi->init_req(_not_equal, fwd); - raw_mem_phi->init_req(_not_equal, raw_mem); + region->init_req(_fwded, if_fwd); + val_phi->init_req(_fwded, fwd); + raw_mem_phi->init_req(_fwded, raw_mem); - // Call wb-stub and wire up that path in slots 4 + // Call lrb-stub and wire up that path in slots 4 Node* result_mem = NULL; - ctrl = if_eq; + ctrl = if_not_fwd; + fwd = new_val; call_lrb_stub(ctrl, fwd, result_mem, raw_mem, phase); region->init_req(_evac_path, ctrl); val_phi->init_req(_evac_path, fwd); @@ -1979,7 +2000,7 @@ nodes.push(root); for (uint next = 0; next < nodes.size(); next++) { Node *n = nodes.at(next); - if (ShenandoahBarrierSetC2::is_shenandoah_wb_call(n)) { + if (ShenandoahBarrierSetC2::is_shenandoah_lrb_call(n)) { controls.push(n); if (trace) { tty->print("XXXXXX verifying"); n->dump(); } for (uint next2 = 0; next2 < controls.size(); next2++) { @@ -2595,7 +2616,11 @@ IdealLoopTree* l = loop; create_phi = false; while (l != _phase->ltree_root()) { - if (_phase->is_dominator(l->_head, u) && _phase->is_dominator(_phase->idom(u), l->_head)) { + Node* head = l->_head; + if (head->in(0) == NULL) { + head = _phase->get_ctrl(head); + } + if (_phase->is_dominator(head, u) && _phase->is_dominator(_phase->idom(u), head)) { create_phi = true; do_check = false; break; @@ -3123,11 +3148,7 @@ break; } case Op_CallStaticJava: { - // If it's an deopt-call we don't need barriers because - // the LRB will be applied when unpacking the deopt frame. - if (n->as_CallStaticJava()->uncommon_trap_request() == 0) { - strength = STRONG; - } + strength = STRONG; break; } case Op_CallDynamicJava:
--- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp Thu May 30 19:51:24 2019 +0200 @@ -60,6 +60,9 @@ stringStream ss; r->print_on(&ss); + stringStream mw_ss; + obj->mark()->print_on(&mw_ss); + ShenandoahMarkingContext* const ctx = heap->marking_context(); msg.append(" " PTR_FORMAT " - klass " PTR_FORMAT " %s\n", p2i(obj), p2i(obj->klass()), obj->klass()->external_name()); @@ -69,6 +72,7 @@ if (heap->traversal_gc() != NULL) { msg.append(" %3s in traversal set\n", heap->traversal_gc()->traversal_set()->is_in((HeapWord*) obj) ? "" : "not"); } + msg.append(" mark:%s\n", mw_ss.as_string()); msg.append(" region: %s", ss.as_string()); } @@ -250,7 +254,7 @@ file, line); } - size_t alloc_size = obj->size() + ShenandoahForwarding::word_size(); + size_t alloc_size = obj->size(); if (alloc_size > ShenandoahHeapRegion::humongous_threshold_words()) { size_t idx = r->region_number(); size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize);
--- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp Thu May 30 19:51:24 2019 +0200 @@ -26,7 +26,6 @@ #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" -#include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahTraversalGC.hpp" @@ -42,7 +41,7 @@ class ShenandoahBarrierSetC1; class ShenandoahBarrierSetC2; -template <bool STOREVAL_WRITE_BARRIER> +template <bool STOREVAL_EVAC_BARRIER> class ShenandoahUpdateRefsForOopClosure: public BasicOopIterateClosure { private: ShenandoahHeap* _heap; @@ -51,7 +50,7 @@ template <class T> inline void do_oop_work(T* p) { oop o; - if (STOREVAL_WRITE_BARRIER) { + if (STOREVAL_EVAC_BARRIER) { o = _heap->evac_update_with_forwarded(p); if (!CompressedOops::is_null(o)) { _bs->enqueue(o); @@ -97,10 +96,10 @@ return true; } -template <class T, bool STOREVAL_WRITE_BARRIER> +template <class T, bool STOREVAL_EVAC_BARRIER> void ShenandoahBarrierSet::write_ref_array_loop(HeapWord* start, size_t count) { assert(UseShenandoahGC && ShenandoahCloneBarrier, "should be enabled"); - ShenandoahUpdateRefsForOopClosure<STOREVAL_WRITE_BARRIER> cl; + ShenandoahUpdateRefsForOopClosure<STOREVAL_EVAC_BARRIER> cl; T* dst = (T*) start; for (size_t i = 0; i < count; i++) { cl.do_oop(dst++); @@ -114,15 +113,15 @@ if (_heap->is_concurrent_traversal_in_progress()) { ShenandoahEvacOOMScope oom_evac_scope; if (UseCompressedOops) { - write_ref_array_loop<narrowOop, /* wb = */ true>(start, count); + write_ref_array_loop<narrowOop, /* evac = */ true>(start, count); } else { - write_ref_array_loop<oop, /* wb = */ true>(start, count); + write_ref_array_loop<oop, /* evac = */ true>(start, count); } } else { if (UseCompressedOops) { - write_ref_array_loop<narrowOop, /* wb = */ false>(start, count); + write_ref_array_loop<narrowOop, /* evac = */ false>(start, count); } else { - write_ref_array_loop<oop, /* wb = */ false>(start, count); + write_ref_array_loop<oop, /* evac = */ false>(start, count); } } } @@ -207,10 +206,10 @@ shenandoah_assert_correct(NULL, obj); if (_heap->is_concurrent_traversal_in_progress()) { ShenandoahEvacOOMScope oom_evac_scope; - ShenandoahUpdateRefsForOopClosure</* wb = */ true> cl; + ShenandoahUpdateRefsForOopClosure</* evac = */ true> cl; obj->oop_iterate(&cl); } else { - ShenandoahUpdateRefsForOopClosure</* wb = */ false> cl; + ShenandoahUpdateRefsForOopClosure</* evac = */ false> cl; obj->oop_iterate(&cl); } } @@ -262,7 +261,7 @@ ShenandoahHeapRegion* r = _heap->heap_region_containing(obj); assert(r->is_cset(), "sanity"); - HeapWord* cur = (HeapWord*)obj + obj->size() + ShenandoahForwarding::word_size(); + HeapWord* cur = (HeapWord*)obj + obj->size(); size_t count = 0; while ((cur < r->top()) && ctx->is_marked(oop(cur)) && (count++ < max)) { @@ -270,7 +269,7 @@ if (oopDesc::equals_raw(cur_oop, resolve_forwarded_not_null(cur_oop))) { _heap->evacuate_object(cur_oop, thread); } - cur = cur + cur_oop->size() + ShenandoahForwarding::word_size(); + cur = cur + cur_oop->size(); } }
--- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp Thu May 30 19:51:24 2019 +0200 @@ -35,8 +35,8 @@ public: enum ArrayCopyStoreValMode { NONE, - READ_BARRIER, - WRITE_BARRIER + RESOLVE_BARRIER, + EVAC_BARRIER }; private:
--- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp Thu May 30 19:51:24 2019 +0200 @@ -199,10 +199,10 @@ switch (storeval_mode) { case NONE: return arraycopy_loop<T, CHECKCAST, SATB, NONE>(src, dst, length, bound, disjoint); - case READ_BARRIER: - return arraycopy_loop<T, CHECKCAST, SATB, READ_BARRIER>(src, dst, length, bound, disjoint); - case WRITE_BARRIER: - return arraycopy_loop<T, CHECKCAST, SATB, WRITE_BARRIER>(src, dst, length, bound, disjoint); + case RESOLVE_BARRIER: + return arraycopy_loop<T, CHECKCAST, SATB, RESOLVE_BARRIER>(src, dst, length, bound, disjoint); + case EVAC_BARRIER: + return arraycopy_loop<T, CHECKCAST, SATB, EVAC_BARRIER>(src, dst, length, bound, disjoint); default: ShouldNotReachHere(); return true; // happy compiler @@ -268,10 +268,10 @@ switch (STOREVAL_MODE) { case NONE: break; - case READ_BARRIER: - case WRITE_BARRIER: - // The write-barrier case cannot really happen. It's traversal-only and traversal - // doesn't currently use SATB. And even if it did, it would not be fatal to just do the normal RB here. + case RESOLVE_BARRIER: + case EVAC_BARRIER: + // The evac-barrier case cannot really happen. It's traversal-only and traversal + // doesn't currently use SATB. And even if it did, it would not be fatal to just do the normal resolve here. prev_obj = ShenandoahBarrierSet::resolve_forwarded_not_null(prev_obj); } if (!ctx->is_marked(prev_obj)) { @@ -293,10 +293,10 @@ switch (STOREVAL_MODE) { case NONE: break; - case READ_BARRIER: + case RESOLVE_BARRIER: obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); break; - case WRITE_BARRIER: + case EVAC_BARRIER: if (_heap->in_collection_set(obj)) { oop forw = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); if (oopDesc::equals_raw(forw, obj)) { @@ -337,9 +337,9 @@ ArrayCopyStoreValMode storeval_mode; if (heap->has_forwarded_objects()) { if (heap->is_concurrent_traversal_in_progress()) { - storeval_mode = WRITE_BARRIER; + storeval_mode = EVAC_BARRIER; } else if (heap->is_update_refs_in_progress()) { - storeval_mode = READ_BARRIER; + storeval_mode = RESOLVE_BARRIER; } else { assert(heap->is_idle() || heap->is_evacuation_in_progress(), "must not have anything in progress"); storeval_mode = NONE; // E.g. during evac or outside cycle
--- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp Thu May 30 19:51:24 2019 +0200 @@ -26,6 +26,7 @@ #include "code/nmethod.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahCodeRoots.hpp" +#include "gc/shenandoah/shenandoahUtils.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" @@ -120,11 +121,10 @@ } }; -ShenandoahCodeRoots::PaddedLock ShenandoahCodeRoots::_recorded_nms_lock; GrowableArray<ShenandoahNMethod*>* ShenandoahCodeRoots::_recorded_nms; +ShenandoahLock ShenandoahCodeRoots::_recorded_nms_lock; void ShenandoahCodeRoots::initialize() { - _recorded_nms_lock._lock = 0; _recorded_nms = new (ResourceObj::C_HEAP, mtGC) GrowableArray<ShenandoahNMethod*>(100, true, mtGC); } @@ -134,15 +134,15 @@ case 1: break; case 2: { + assert_locked_or_safepoint(CodeCache_lock); + ShenandoahLocker locker(CodeCache_lock->owned_by_self() ? NULL : &_recorded_nms_lock); + ShenandoahNMethodOopDetector detector; nm->oops_do(&detector); if (detector.has_oops()) { ShenandoahNMethod* nmr = new ShenandoahNMethod(nm, detector.oops()); nmr->assert_alive_and_correct(); - - ShenandoahCodeRootsLock lock(true); - int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod); if (idx != -1) { ShenandoahNMethod* old = _recorded_nms->at(idx); @@ -166,12 +166,13 @@ break; } case 2: { + assert_locked_or_safepoint(CodeCache_lock); + ShenandoahLocker locker(CodeCache_lock->owned_by_self() ? NULL : &_recorded_nms_lock); + ShenandoahNMethodOopDetector detector; nm->oops_do(&detector, /* allow_zombie = */ true); if (detector.has_oops()) { - ShenandoahCodeRootsLock lock(true); - int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod); assert(idx != -1, "nmethod " PTR_FORMAT " should be registered", p2i(nm)); ShenandoahNMethod* old = _recorded_nms->at(idx); @@ -199,7 +200,7 @@ break; } case 2: { - ShenandoahCodeRoots::acquire_lock(false); + CodeCache_lock->lock(); break; } default: @@ -215,7 +216,7 @@ break; } case 2: { - ShenandoahCodeRoots::release_lock(false); + CodeCache_lock->unlock(); break; } default: @@ -245,14 +246,6 @@ } } -ShenandoahAllCodeRootsIterator ShenandoahCodeRoots::iterator() { - return ShenandoahAllCodeRootsIterator(); -} - -ShenandoahCsetCodeRootsIterator ShenandoahCodeRoots::cset_iterator() { - return ShenandoahCsetCodeRootsIterator(); -} - void ShenandoahAllCodeRootsIterator::possibly_parallel_blobs_do(CodeBlobClosure *f) { ShenandoahCodeRootsIterator::dispatch_parallel_blobs_do<false>(f); }
--- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp Thu May 30 19:51:24 2019 +0200 @@ -26,12 +26,12 @@ #include "code/codeCache.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" class ShenandoahHeap; class ShenandoahHeapRegion; -class ShenandoahCodeRootsLock; class ShenandoahParallelCodeHeapIterator { friend class CodeCache; @@ -51,6 +51,11 @@ private: ShenandoahParallelCodeHeapIterator* _iters; int _length; + +private: + // Noncopyable. + ShenandoahParallelCodeCacheIterator(const ShenandoahParallelCodeCacheIterator& o); + ShenandoahParallelCodeCacheIterator& operator=(const ShenandoahParallelCodeCacheIterator& o); public: ShenandoahParallelCodeCacheIterator(const GrowableArray<CodeHeap*>* heaps); ~ShenandoahParallelCodeCacheIterator(); @@ -119,7 +124,6 @@ class ShenandoahCodeRoots : public CHeapObj<mtGC> { friend class ShenandoahHeap; - friend class ShenandoahCodeRootsLock; friend class ShenandoahCodeRootsIterator; public: @@ -127,74 +131,9 @@ static void add_nmethod(nmethod* nm); static void remove_nmethod(nmethod* nm); - /** - * Provides the iterator over all nmethods in the code cache that have oops. - * @return - */ - static ShenandoahAllCodeRootsIterator iterator(); - - /** - * Provides the iterator over nmethods that have at least one oop in collection set. - * @return - */ - static ShenandoahCsetCodeRootsIterator cset_iterator(); - private: - struct PaddedLock { - DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile int)); - volatile int _lock; - DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0); - }; - - static PaddedLock _recorded_nms_lock; static GrowableArray<ShenandoahNMethod*>* _recorded_nms; - - static void acquire_lock(bool write) { - volatile int* loc = &_recorded_nms_lock._lock; - if (write) { - while ((OrderAccess::load_acquire(loc) != 0) || - Atomic::cmpxchg(-1, loc, 0) != 0) { - SpinPause(); - } - assert (*loc == -1, "acquired for write"); - } else { - while (true) { - int cur = OrderAccess::load_acquire(loc); - if (cur >= 0) { - if (Atomic::cmpxchg(cur + 1, loc, cur) == cur) { - // Success! - assert (*loc > 0, "acquired for read"); - return; - } - } - SpinPause(); - } - } - } - - static void release_lock(bool write) { - volatile int* loc = &ShenandoahCodeRoots::_recorded_nms_lock._lock; - if (write) { - OrderAccess::release_store_fence(loc, 0); - } else { - Atomic::dec(loc); - } - } -}; - -// Very simple unranked read-write lock -class ShenandoahCodeRootsLock : public StackObj { - friend class ShenandoahCodeRoots; -private: - const bool _write; -public: - ShenandoahCodeRootsLock(bool write) : _write(write) { - ShenandoahCodeRoots::acquire_lock(write); - } - - ~ShenandoahCodeRootsLock() { - ShenandoahCodeRoots::release_lock(_write); - } + static ShenandoahLock _recorded_nms_lock; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.inline.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.inline.hpp Thu May 30 19:51:24 2019 +0200 @@ -25,7 +25,6 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_INLINE_HPP #include "gc/shenandoah/shenandoahAsserts.hpp" -#include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" @@ -70,7 +69,7 @@ inline void ShenandoahConcurrentMark::count_liveness(jushort* live_data, oop obj) { size_t region_idx = _heap->heap_region_index_containing(obj); ShenandoahHeapRegion* region = _heap->get_region(region_idx); - size_t size = obj->size() + ShenandoahForwarding::word_size(); + size_t size = obj->size(); if (!region->is_humongous_start()) { assert(!region->is_humongous(), "Cannot have continuations here");
--- a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.hpp Thu May 30 19:51:24 2019 +0200 @@ -28,68 +28,11 @@ #include "utilities/globalDefinitions.hpp" class ShenandoahForwarding { - /* - * Notes: - * - * a. It is important to have byte_offset and word_offset return constant - * expressions, because that will allow to constant-fold forwarding ptr - * accesses. This is not a problem in JIT compilers that would generate - * the code once, but it is problematic in GC hotpath code. - * - * b. With filler object mechanics, we may need to allocate more space for - * the forwarding ptr to meet alignment requirements for objects. This - * means *_offset and *_size calls are NOT interchangeable. The accesses - * to forwarding ptrs should always be via *_offset. Storage size - * calculations should always be via *_size. - */ - public: - /* Offset from the object start, in HeapWords. */ - static inline int word_offset() { - return -1; // exactly one HeapWord - } - - /* Offset from the object start, in bytes. */ - static inline int byte_offset() { - return -HeapWordSize; // exactly one HeapWord - } - - /* Allocated size, in HeapWords. */ - static inline uint word_size() { - return (uint) MinObjAlignment; - } - - /* Allocated size, in bytes */ - static inline uint byte_size() { - return (uint) MinObjAlignmentInBytes; - } - - /* Assert basic stuff once at startup. */ - static void initial_checks() { - guarantee (MinObjAlignment > 0, "sanity, word_size is correct"); - guarantee (MinObjAlignmentInBytes > 0, "sanity, byte_size is correct"); - } - - /* Initializes forwarding pointer (to self). - */ - static inline void initialize(oop obj); - /* Gets forwardee from the given object. */ static inline oop get_forwardee(oop obj); - /* Tries to atomically update forwardee in $holder object to $update. - * Assumes $holder points at itself. - * Asserts $holder is in from-space. - * Asserts $update is in to-space. - */ - static inline oop try_update_forwardee(oop obj, oop update); - - /* Sets raw value for forwardee slot. - * THIS IS DANGEROUS: USERS HAVE TO INITIALIZE/SET FORWARDEE BACK AFTER THEY ARE DONE. - */ - static inline void set_forwardee_raw(oop obj, HeapWord* update); - /* Returns the raw value from forwardee slot. */ static inline HeapWord* get_forwardee_raw(oop obj); @@ -99,8 +42,21 @@ */ static inline HeapWord* get_forwardee_raw_unchecked(oop obj); -private: - static inline HeapWord** forward_ptr_addr(oop obj); + /** + * Returns true if the object is forwarded, false otherwise. + */ + static inline bool is_forwarded(oop obj); + + /* Tries to atomically update forwardee in $holder object to $update. + * Assumes $holder points at itself. + * Asserts $holder is in from-space. + * Asserts $update is in to-space. + * + * Returns the new object 'update' upon success, or + * the new forwardee that a competing thread installed. + */ + static inline oop try_update_forwardee(oop obj, oop update); + }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHFORWARDING_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp Thu May 30 19:51:24 2019 +0200 @@ -26,40 +26,45 @@ #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" +#include "oops/markOop.inline.hpp" #include "runtime/atomic.hpp" -inline HeapWord** ShenandoahForwarding::forward_ptr_addr(oop obj) { - return (HeapWord**)((HeapWord*) obj + word_offset()); -} - -inline void ShenandoahForwarding::initialize(oop obj) { - shenandoah_assert_in_heap(NULL, obj); - *forward_ptr_addr(obj) = (HeapWord*) obj; -} - -inline void ShenandoahForwarding::set_forwardee_raw(oop obj, HeapWord* update) { - shenandoah_assert_in_heap(NULL, obj); - *forward_ptr_addr(obj) = update; -} - inline HeapWord* ShenandoahForwarding::get_forwardee_raw(oop obj) { shenandoah_assert_in_heap(NULL, obj); - return *forward_ptr_addr(obj); + return get_forwardee_raw_unchecked(obj); } inline HeapWord* ShenandoahForwarding::get_forwardee_raw_unchecked(oop obj) { - return *forward_ptr_addr(obj); + markOop mark = obj->mark_raw(); + if (mark->is_marked()) { + return (HeapWord*) mark->clear_lock_bits(); + } else { + return (HeapWord*) obj; + } } inline oop ShenandoahForwarding::get_forwardee(oop obj) { shenandoah_assert_correct(NULL, obj); - return oop(*forward_ptr_addr(obj)); + return oop(get_forwardee_raw_unchecked(obj)); +} + +inline bool ShenandoahForwarding::is_forwarded(oop obj) { + return obj->mark_raw()->is_marked(); } inline oop ShenandoahForwarding::try_update_forwardee(oop obj, oop update) { - oop result = (oop) Atomic::cmpxchg(update, (oop*)forward_ptr_addr(obj), obj); - shenandoah_assert_correct_except(NULL, obj, !oopDesc::equals_raw(result, obj)); - return result; + markOop old_mark = obj->mark_raw(); + if (old_mark->is_marked()) { + return (oop) old_mark->clear_lock_bits(); + } + + markOop new_mark = markOopDesc::encode_pointer_as_mark(update); + markOop prev_mark = obj->cas_set_mark_raw(new_mark, old_mark); + if (prev_mark == old_mark) { + return update; + } else { + return (oop) prev_mark->clear_lock_bits(); + } } #endif // SHARE_GC_SHENANDOAH_SHENANDOAHFORWARDING_INLINE_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Thu May 30 19:51:24 2019 +0200 @@ -34,7 +34,6 @@ #include "gc/shenandoah/shenandoahAllocTracker.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" -#include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -139,8 +138,6 @@ }; jint ShenandoahHeap::initialize() { - ShenandoahForwarding::initial_checks(); - initialize_heuristics(); // @@ -876,49 +873,6 @@ return _free_set->allocate(req, in_new_region); } -class ShenandoahMemAllocator : public MemAllocator { -private: - MemAllocator& _initializer; -public: - ShenandoahMemAllocator(MemAllocator& initializer, Klass* klass, size_t word_size, Thread* thread) : - MemAllocator(klass, word_size + ShenandoahForwarding::word_size(), thread), - _initializer(initializer) {} - -protected: - virtual HeapWord* mem_allocate(Allocation& allocation) const { - HeapWord* result = MemAllocator::mem_allocate(allocation); - // Initialize brooks-pointer - if (result != NULL) { - result += ShenandoahForwarding::word_size(); - ShenandoahForwarding::initialize(oop(result)); - assert(! ShenandoahHeap::heap()->in_collection_set(result), "never allocate in targetted region"); - } - return result; - } - - virtual oop initialize(HeapWord* mem) const { - return _initializer.initialize(mem); - } -}; - -oop ShenandoahHeap::obj_allocate(Klass* klass, int size, TRAPS) { - ObjAllocator initializer(klass, size, THREAD); - ShenandoahMemAllocator allocator(initializer, klass, size, THREAD); - return allocator.allocate(); -} - -oop ShenandoahHeap::array_allocate(Klass* klass, int size, int length, bool do_zero, TRAPS) { - ObjArrayAllocator initializer(klass, size, length, do_zero, THREAD); - ShenandoahMemAllocator allocator(initializer, klass, size, THREAD); - return allocator.allocate(); -} - -oop ShenandoahHeap::class_allocate(Klass* klass, int size, TRAPS) { - ClassAllocator initializer(klass, size, THREAD); - ShenandoahMemAllocator allocator(initializer, klass, size, THREAD); - return allocator.allocate(); -} - HeapWord* ShenandoahHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) { ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared(size); @@ -961,15 +915,6 @@ return NULL; } -void ShenandoahHeap::fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) { - HeapWord* obj = tlab_post_allocation_setup(start); - CollectedHeap::fill_with_object(obj, end); -} - -size_t ShenandoahHeap::min_dummy_object_size() const { - return CollectedHeap::min_dummy_object_size() + ShenandoahForwarding::word_size(); -} - class ShenandoahConcurrentEvacuateRegionObjectClosure : public ObjectClosure { private: ShenandoahHeap* const _heap; @@ -980,7 +925,7 @@ void do_object(oop p) { shenandoah_assert_marked(NULL, p); - if (oopDesc::equals_raw(p, ShenandoahBarrierSet::resolve_forwarded_not_null(p))) { + if (!p->is_forwarded()) { _heap->evacuate_object(p, _thread); } } @@ -1060,8 +1005,8 @@ void ShenandoahHeap::trash_humongous_region_at(ShenandoahHeapRegion* start) { assert(start->is_humongous_start(), "reclaim regions starting with the first one"); - oop humongous_obj = oop(start->bottom() + ShenandoahForwarding::word_size()); - size_t size = humongous_obj->size() + ShenandoahForwarding::word_size(); + oop humongous_obj = oop(start->bottom()); + size_t size = humongous_obj->size(); size_t required_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize); size_t index = start->region_number() + required_regions - 1; @@ -1874,13 +1819,6 @@ set_gc_state_mask(EVACUATION, in_progress); } -HeapWord* ShenandoahHeap::tlab_post_allocation_setup(HeapWord* obj) { - // Initialize Brooks pointer for the next object - HeapWord* result = obj + ShenandoahForwarding::word_size(); - ShenandoahForwarding::initialize(oop(result)); - return result; -} - void ShenandoahHeap::ref_processing_init() { assert(_max_workers > 0, "Sanity"); @@ -2853,11 +2791,3 @@ } } } - -size_t ShenandoahHeap::obj_size(oop obj) const { - return CollectedHeap::obj_size(obj) + ShenandoahForwarding::word_size(); -} - -ptrdiff_t ShenandoahHeap::cell_header_size() const { - return ShenandoahForwarding::byte_size(); -}
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp Thu May 30 19:51:24 2019 +0200 @@ -29,7 +29,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahAllocRequest.hpp" -#include "gc/shenandoah/shenandoahHeapLock.hpp" +#include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahEvacOOMHandler.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "services/memoryManager.hpp" @@ -103,6 +103,8 @@ }; #endif +typedef ShenandoahLock ShenandoahHeapLock; +typedef ShenandoahLocker ShenandoahHeapLocker; // Shenandoah GC is low-pause concurrent GC that uses Brooks forwarding pointers // to encode forwarding data. See BrooksPointer for details on forwarding data encoding. @@ -520,9 +522,6 @@ bool is_in(const void* p) const; - size_t obj_size(oop obj) const; - virtual ptrdiff_t cell_header_size() const; - void collect(GCCause::Cause cause); void do_full_collection(bool clear_all_soft_refs); @@ -576,10 +575,6 @@ size_t size, Metaspace::MetadataType mdtype); - oop obj_allocate(Klass* klass, int size, TRAPS); - oop array_allocate(Klass* klass, int size, int length, bool do_zero, TRAPS); - oop class_allocate(Klass* klass, int size, TRAPS); - void notify_mutator_alloc_words(size_t words, bool waste); // Shenandoah supports TLAB allocation @@ -591,10 +586,6 @@ size_t max_tlab_size() const; size_t tlab_used(Thread* ignored) const; - HeapWord* tlab_post_allocation_setup(HeapWord* obj); - void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap); - size_t min_dummy_object_size() const; - void resize_tlabs(); void ensure_parsability(bool retire_tlabs);
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp Thu May 30 19:51:24 2019 +0200 @@ -235,51 +235,46 @@ assert(ShenandoahThreadLocalData::is_evac_allowed(thread), "must be enclosed in oom-evac scope"); - size_t size_no_fwdptr = (size_t) p->size(); - size_t size_with_fwdptr = size_no_fwdptr + ShenandoahForwarding::word_size(); + size_t size = p->size(); assert(!heap_region_containing(p)->is_humongous(), "never evacuate humongous objects"); bool alloc_from_gclab = true; - HeapWord* filler = NULL; + HeapWord* copy = NULL; #ifdef ASSERT if (ShenandoahOOMDuringEvacALot && (os::random() & 1) == 0) { // Simulate OOM every ~2nd slow-path call - filler = NULL; + copy = NULL; } else { #endif if (UseTLAB) { - filler = allocate_from_gclab(thread, size_with_fwdptr); + copy = allocate_from_gclab(thread, size); } - if (filler == NULL) { - ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size_with_fwdptr); - filler = allocate_memory(req); + if (copy == NULL) { + ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(size); + copy = allocate_memory(req); alloc_from_gclab = false; } #ifdef ASSERT } #endif - if (filler == NULL) { - control_thread()->handle_alloc_failure_evac(size_with_fwdptr); + if (copy == NULL) { + control_thread()->handle_alloc_failure_evac(size); _oom_evac_handler.handle_out_of_memory_during_evacuation(); return ShenandoahBarrierSet::resolve_forwarded(p); } - // Copy the object and initialize its forwarding ptr: - HeapWord* copy = filler + ShenandoahForwarding::word_size(); - oop copy_val = oop(copy); - - Copy::aligned_disjoint_words((HeapWord*) p, copy, size_no_fwdptr); - ShenandoahForwarding::initialize(oop(copy)); + // Copy the object: + Copy::aligned_disjoint_words((HeapWord*) p, copy, size); // Try to install the new forwarding pointer. + oop copy_val = oop(copy); oop result = ShenandoahForwarding::try_update_forwardee(p, copy_val); - - if (oopDesc::equals_raw(result, p)) { + if (oopDesc::equals_raw(result, copy_val)) { // Successfully evacuated. Our copy is now the public one! shenandoah_assert_correct(NULL, copy_val); return copy_val; @@ -296,11 +291,11 @@ // have to explicitly overwrite the copy with the filler object. With that overwrite, // we have to keep the fwdptr initialized and pointing to our (stale) copy. if (alloc_from_gclab) { - ShenandoahThreadLocalData::gclab(thread)->undo_allocation(filler, size_with_fwdptr); + ShenandoahThreadLocalData::gclab(thread)->undo_allocation(copy, size); } else { - fill_with_object(copy, size_no_fwdptr); + fill_with_object(copy, size); + shenandoah_assert_correct(NULL, copy_val); } - shenandoah_assert_correct(NULL, copy_val); shenandoah_assert_correct(NULL, result); return result; } @@ -371,7 +366,6 @@ template<class T> inline void ShenandoahHeap::marked_object_iterate(ShenandoahHeapRegion* region, T* cl, HeapWord* limit) { - assert(ShenandoahForwarding::word_offset() < 0, "skip_delta calculation below assumes the forwarding ptr is before obj"); assert(! region->is_humongous_continuation(), "no humongous continuation regions here"); ShenandoahMarkingContext* const ctx = complete_marking_context(); @@ -380,10 +374,9 @@ MarkBitMap* mark_bit_map = ctx->mark_bit_map(); HeapWord* tams = ctx->top_at_mark_start(region); - size_t skip_bitmap_delta = ShenandoahForwarding::word_size() + 1; - size_t skip_objsize_delta = ShenandoahForwarding::word_size() /* + actual obj.size() below */; - HeapWord* start = region->bottom() + ShenandoahForwarding::word_size(); - HeapWord* end = MIN2(tams + ShenandoahForwarding::word_size(), region->end()); + size_t skip_bitmap_delta = 1; + HeapWord* start = region->bottom(); + HeapWord* end = MIN2(tams, region->end()); // Step 1. Scan below the TAMS based on bitmap data. HeapWord* limit_bitmap = MIN2(limit, tams); @@ -413,7 +406,7 @@ do { avail = 0; for (int c = 0; (c < dist) && (cb < limit_bitmap); c++) { - Prefetch::read(cb, ShenandoahForwarding::byte_offset()); + Prefetch::read(cb, oopDesc::mark_offset_in_bytes()); slots[avail++] = cb; cb += skip_bitmap_delta; if (cb < limit_bitmap) { @@ -448,16 +441,16 @@ // Step 2. Accurate size-based traversal, happens past the TAMS. // This restarts the scan at TAMS, which makes sure we traverse all objects, // regardless of what happened at Step 1. - HeapWord* cs = tams + ShenandoahForwarding::word_size(); + HeapWord* cs = tams; while (cs < limit) { - assert (cs > tams, "only objects past TAMS here: " PTR_FORMAT " (" PTR_FORMAT ")", p2i(cs), p2i(tams)); + assert (cs >= tams, "only objects past TAMS here: " PTR_FORMAT " (" PTR_FORMAT ")", p2i(cs), p2i(tams)); assert (cs < limit, "only objects below limit here: " PTR_FORMAT " (" PTR_FORMAT ")", p2i(cs), p2i(limit)); oop obj = oop(cs); assert(oopDesc::is_oop(obj), "sanity"); assert(ctx->is_marked(obj), "object expected to be marked"); int size = obj->size(); cl->do_object(obj); - cs += size + skip_objsize_delta; + cs += size; } }
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapLock.hpp Thu May 23 22:14:23 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHHEAPLOCK_HPP -#define SHARE_GC_SHENANDOAH_SHENANDOAHHEAPLOCK_HPP - -#include "memory/allocation.hpp" -#include "runtime/thread.hpp" - -class ShenandoahHeapLock { -private: - enum LockState { unlocked = 0, locked = 1 }; - - DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile int)); - volatile int _state; - DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile Thread*)); - volatile Thread* _owner; - DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 0); - -public: - ShenandoahHeapLock() : _state(unlocked), _owner(NULL) {}; - - void lock() { - Thread::SpinAcquire(&_state, "Shenandoah Heap Lock"); -#ifdef ASSERT - assert(_state == locked, "must be locked"); - assert(_owner == NULL, "must not be owned"); - _owner = Thread::current(); -#endif - } - - void unlock() { -#ifdef ASSERT - assert (_owner == Thread::current(), "sanity"); - _owner = NULL; -#endif - Thread::SpinRelease(&_state); - } - -#ifdef ASSERT - void assert_owned_by_current_thread() { - assert(_state == locked, "must be locked"); - assert(_owner == Thread::current(), "must be owned by current thread"); - } - - void assert_not_owned_by_current_thread() { - assert(_owner != Thread::current(), "must be not owned by current thread"); - } - - void assert_owned_by_current_thread_or_safepoint() { - Thread* thr = Thread::current(); - assert((_state == locked && _owner == thr) || - (SafepointSynchronize::is_at_safepoint() && thr->is_VM_thread()), - "must own heap lock or by VM thread at safepoint"); - } -#endif -}; - -class ShenandoahHeapLocker : public StackObj { -private: - ShenandoahHeapLock* _lock; -public: - ShenandoahHeapLocker(ShenandoahHeapLock* lock) { - _lock = lock; - _lock->lock(); - } - - ~ShenandoahHeapLocker() { - _lock->unlock(); - } -}; - -#endif // SHARE_GC_SHENANDOAH_SHENANDOAHHEAPLOCK_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp Thu May 30 19:51:24 2019 +0200 @@ -23,7 +23,6 @@ #include "precompiled.hpp" #include "memory/allocation.hpp" -#include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" @@ -453,12 +452,12 @@ void ShenandoahHeapRegion::oop_iterate_objects(OopIterateClosure* blk) { assert(! is_humongous(), "no humongous region here"); - HeapWord* obj_addr = bottom() + ShenandoahForwarding::word_size(); + HeapWord* obj_addr = bottom(); HeapWord* t = top(); // Could call objects iterate, but this is easier. while (obj_addr < t) { oop obj = oop(obj_addr); - obj_addr += obj->oop_iterate_size(blk) + ShenandoahForwarding::word_size(); + obj_addr += obj->oop_iterate_size(blk); } } @@ -467,7 +466,7 @@ // Find head. ShenandoahHeapRegion* r = humongous_start_region(); assert(r->is_humongous_start(), "need humongous head here"); - oop obj = oop(r->bottom() + ShenandoahForwarding::word_size()); + oop obj = oop(r->bottom()); obj->oop_iterate(blk, MemRegion(bottom(), top())); } @@ -506,11 +505,11 @@ if (p >= top()) { return top(); } else { - HeapWord* last = bottom() + ShenandoahForwarding::word_size(); + HeapWord* last = bottom(); HeapWord* cur = last; while (cur <= p) { last = cur; - cur += oop(cur)->size() + ShenandoahForwarding::word_size(); + cur += oop(cur)->size(); } shenandoah_assert_correct(NULL, oop(last)); return last;
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeuristics.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeuristics.cpp Thu May 30 19:51:24 2019 +0200 @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "gc/shared/gcCause.hpp" -#include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" @@ -164,7 +163,7 @@ // Reclaim humongous regions here, and count them as the immediate garbage #ifdef ASSERT bool reg_live = region->has_live(); - bool bm_live = ctx->is_marked(oop(region->bottom() + ShenandoahForwarding::word_size())); + bool bm_live = ctx->is_marked(oop(region->bottom())); assert(reg_live == bm_live, "Humongous liveness and marks should agree. Region live: %s; Bitmap live: %s; Region Live Words: " SIZE_FORMAT, BOOL_TO_STR(reg_live), BOOL_TO_STR(bm_live), region->get_live_data_words());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp Thu May 30 19:51:24 2019 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHLOCK_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHLOCK_HPP + +#include "memory/allocation.hpp" +#include "runtime/thread.hpp" + +class ShenandoahLock { +private: + enum LockState { unlocked = 0, locked = 1 }; + + DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile int)); + volatile int _state; + DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile Thread*)); + volatile Thread* _owner; + DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 0); + +public: + ShenandoahLock() : _state(unlocked), _owner(NULL) {}; + + void lock() { + Thread::SpinAcquire(&_state, "Shenandoah Heap Lock"); +#ifdef ASSERT + assert(_state == locked, "must be locked"); + assert(_owner == NULL, "must not be owned"); + _owner = Thread::current(); +#endif + } + + void unlock() { +#ifdef ASSERT + assert (_owner == Thread::current(), "sanity"); + _owner = NULL; +#endif + Thread::SpinRelease(&_state); + } + +#ifdef ASSERT + void assert_owned_by_current_thread() { + assert(_state == locked, "must be locked"); + assert(_owner == Thread::current(), "must be owned by current thread"); + } + + void assert_not_owned_by_current_thread() { + assert(_owner != Thread::current(), "must be not owned by current thread"); + } + + void assert_owned_by_current_thread_or_safepoint() { + Thread* thr = Thread::current(); + assert((_state == locked && _owner == thr) || + (SafepointSynchronize::is_at_safepoint() && thr->is_VM_thread()), + "must own heap lock or by VM thread at safepoint"); + } +#endif +}; + +class ShenandoahLocker : public StackObj { +private: + ShenandoahLock* const _lock; +public: + ShenandoahLocker(ShenandoahLock* lock) : _lock(lock) { + if (_lock != NULL) { + _lock->lock(); + } + } + + ~ShenandoahLocker() { + if (_lock != NULL) { + _lock->unlock(); + } + } +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHLOCK_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp Thu May 30 19:51:24 2019 +0200 @@ -25,6 +25,7 @@ #include "code/codeCache.hpp" #include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shenandoah/shenandoahForwarding.inline.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" @@ -46,11 +47,16 @@ #include "memory/universe.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/biasedLocking.hpp" #include "runtime/thread.hpp" #include "utilities/copy.hpp" #include "utilities/growableArray.hpp" #include "gc/shared/workgroup.hpp" +ShenandoahMarkCompact::ShenandoahMarkCompact() : + _gc_timer(NULL), + _preserved_marks(new PreservedMarksSet(true)) {} + void ShenandoahMarkCompact::initialize(GCTimer* gc_timer) { _gc_timer = gc_timer; } @@ -121,6 +127,10 @@ // e. Set back forwarded objects bit back, in case some steps above dropped it. heap->set_has_forwarded_objects(has_forwarded_objects); + + // The rest of prologue: + BiasedLocking::preserve_marks(); + _preserved_marks->init(heap->workers()->active_workers()); } heap->make_parsable(true); @@ -159,6 +169,16 @@ phase4_compact_objects(worker_slices); } + { + // Epilogue + SharedRestorePreservedMarksTaskExecutor exec(heap->workers()); + _preserved_marks->restore(&exec); + BiasedLocking::restore_marks(); + _preserved_marks->reclaim(); + + JvmtiExport::gc_epilogue(); + } + // Resize metaspace MetaspaceGC::compute_new_size(); @@ -168,8 +188,6 @@ } FREE_C_HEAP_ARRAY(ShenandoahHeapRegionSet*, worker_slices); - JvmtiExport::gc_epilogue(); - heap->set_full_gc_move_in_progress(false); heap->set_full_gc_in_progress(false); @@ -230,6 +248,7 @@ class ShenandoahPrepareForCompactionObjectClosure : public ObjectClosure { private: + PreservedMarks* const _preserved_marks; ShenandoahHeap* const _heap; GrowableArray<ShenandoahHeapRegion*>& _empty_regions; int _empty_regions_pos; @@ -238,7 +257,10 @@ HeapWord* _compact_point; public: - ShenandoahPrepareForCompactionObjectClosure(GrowableArray<ShenandoahHeapRegion*>& empty_regions, ShenandoahHeapRegion* to_region) : + ShenandoahPrepareForCompactionObjectClosure(PreservedMarks* preserved_marks, + GrowableArray<ShenandoahHeapRegion*>& empty_regions, + ShenandoahHeapRegion* to_region) : + _preserved_marks(preserved_marks), _heap(ShenandoahHeap::heap()), _empty_regions(empty_regions), _empty_regions_pos(0), @@ -268,7 +290,7 @@ assert(_heap->complete_marking_context()->is_marked(p), "must be marked"); assert(!_heap->complete_marking_context()->allocated_after_mark_start((HeapWord*) p), "must be truly marked"); - size_t obj_size = p->size() + ShenandoahForwarding::word_size(); + size_t obj_size = p->size(); if (_compact_point + obj_size > _to_region->end()) { finish_region(); @@ -291,13 +313,15 @@ // Object fits into current region, record new location: assert(_compact_point + obj_size <= _to_region->end(), "must fit"); shenandoah_assert_not_forwarded(NULL, p); - ShenandoahForwarding::set_forwardee_raw(p, _compact_point + ShenandoahForwarding::word_size()); + _preserved_marks->push_if_necessary(p, p->mark_raw()); + p->forward_to(oop(_compact_point)); _compact_point += obj_size; } }; class ShenandoahPrepareForCompactionTask : public AbstractGangTask { private: + PreservedMarksSet* const _preserved_marks; ShenandoahHeap* const _heap; ShenandoahHeapRegionSet** const _worker_slices; ShenandoahRegionIterator _heap_regions; @@ -320,8 +344,9 @@ } public: - ShenandoahPrepareForCompactionTask(ShenandoahHeapRegionSet** worker_slices) : + ShenandoahPrepareForCompactionTask(PreservedMarksSet* preserved_marks, ShenandoahHeapRegionSet** worker_slices) : AbstractGangTask("Shenandoah Prepare For Compaction Task"), + _preserved_marks(preserved_marks), _heap(ShenandoahHeap::heap()), _worker_slices(worker_slices) { } @@ -337,7 +362,7 @@ // Remember empty regions and reuse them as needed. ResourceMark rm; GrowableArray<ShenandoahHeapRegion*> empty_regions((int)_heap->num_regions()); - ShenandoahPrepareForCompactionObjectClosure cl(empty_regions, from_region); + ShenandoahPrepareForCompactionObjectClosure cl(_preserved_marks->get(worker_id), empty_regions, from_region); while (from_region != NULL) { cl.set_from_region(from_region); if (from_region->has_live()) { @@ -377,8 +402,8 @@ size_t to_begin = heap->num_regions(); size_t to_end = heap->num_regions(); - for (size_t c = heap->num_regions() - 1; c > 0; c--) { - ShenandoahHeapRegion *r = heap->get_region(c); + for (size_t c = heap->num_regions(); c > 0; c--) { + ShenandoahHeapRegion *r = heap->get_region(c - 1); if (r->is_humongous_continuation() || (r->new_top() == r->bottom())) { // To-region candidate: record this, and continue scan to_begin = r->region_number(); @@ -387,15 +412,16 @@ if (r->is_humongous_start() && r->is_move_allowed()) { // From-region candidate: movable humongous region - oop old_obj = oop(r->bottom() + ShenandoahForwarding::word_size()); - size_t words_size = old_obj->size() + ShenandoahForwarding::word_size(); + oop old_obj = oop(r->bottom()); + size_t words_size = old_obj->size(); size_t num_regions = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize); size_t start = to_end - num_regions; if (start >= to_begin && start != r->region_number()) { // Fits into current window, and the move is non-trivial. Record the move then, and continue scan. - ShenandoahForwarding::set_forwardee_raw(old_obj, heap->get_region(start)->bottom() + ShenandoahForwarding::word_size()); + _preserved_marks->get(0)->push_if_necessary(old_obj, old_obj->mark_raw()); + old_obj->forward_to(oop(heap->get_region(start)->bottom())); to_end = start; continue; } @@ -443,7 +469,7 @@ void heap_region_do(ShenandoahHeapRegion* r) { if (r->is_humongous_start()) { - oop humongous_obj = oop(r->bottom() + ShenandoahForwarding::word_size()); + oop humongous_obj = oop(r->bottom()); if (!_ctx->is_marked(humongous_obj)) { assert(!r->has_live(), "Region " SIZE_FORMAT " is not marked, should not have live", r->region_number()); @@ -484,7 +510,7 @@ // Compute the new addresses for regular objects { ShenandoahGCPhase phase(ShenandoahPhaseTimings::full_gc_calculate_addresses_regular); - ShenandoahPrepareForCompactionTask prepare_task(worker_slices); + ShenandoahPrepareForCompactionTask prepare_task(_preserved_marks, worker_slices); heap->workers()->run_task(&prepare_task); } @@ -506,8 +532,10 @@ if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); assert(_ctx->is_marked(obj), "must be marked"); - oop forw = oop(ShenandoahForwarding::get_forwardee_raw(obj)); - RawAccess<IS_NOT_NULL>::oop_store(p, forw); + if (obj->is_forwarded()) { + oop forw = obj->forwardee(); + RawAccess<IS_NOT_NULL>::oop_store(p, forw); + } } } @@ -531,7 +559,6 @@ } void do_object(oop p) { assert(_heap->complete_marking_context()->is_marked(p), "must be marked"); - HeapWord* forw = ShenandoahForwarding::get_forwardee_raw(p); p->oop_iterate(&_cl); } }; @@ -562,15 +589,17 @@ class ShenandoahAdjustRootPointersTask : public AbstractGangTask { private: ShenandoahRootAdjuster* _rp; - + PreservedMarksSet* _preserved_marks; public: - ShenandoahAdjustRootPointersTask(ShenandoahRootAdjuster* rp) : + ShenandoahAdjustRootPointersTask(ShenandoahRootAdjuster* rp, PreservedMarksSet* preserved_marks) : AbstractGangTask("Shenandoah Adjust Root Pointers Task"), - _rp(rp) {} + _rp(rp), + _preserved_marks(preserved_marks) {} void work(uint worker_id) { ShenandoahAdjustPointersClosure cl; _rp->roots_do(worker_id, &cl); + _preserved_marks->get(worker_id)->adjust_during_full_gc(); } }; @@ -587,7 +616,7 @@ DerivedPointerTable::clear(); #endif ShenandoahRootAdjuster rp(nworkers, ShenandoahPhaseTimings::full_gc_roots); - ShenandoahAdjustRootPointersTask task(&rp); + ShenandoahAdjustRootPointersTask task(&rp, _preserved_marks); workers->run_task(&task); #if COMPILER2_OR_JVMCI DerivedPointerTable::update_pointers(); @@ -610,13 +639,13 @@ void do_object(oop p) { assert(_heap->complete_marking_context()->is_marked(p), "must be marked"); size_t size = (size_t)p->size(); - HeapWord* compact_to = ShenandoahForwarding::get_forwardee_raw(p); - HeapWord* compact_from = (HeapWord*) p; - if (compact_from != compact_to) { + if (p->is_forwarded()) { + HeapWord* compact_from = (HeapWord*) p; + HeapWord* compact_to = (HeapWord*) p->forwardee(); Copy::aligned_conjoint_words(compact_from, compact_to, size); + oop new_obj = oop(compact_to); + new_obj->init_mark_raw(); } - oop new_obj = oop(compact_to); - ShenandoahForwarding::initialize(new_obj); } }; @@ -707,31 +736,30 @@ ShenandoahHeap* heap = ShenandoahHeap::heap(); - for (size_t c = heap->num_regions() - 1; c > 0; c--) { - ShenandoahHeapRegion* r = heap->get_region(c); + for (size_t c = heap->num_regions(); c > 0; c--) { + ShenandoahHeapRegion* r = heap->get_region(c - 1); if (r->is_humongous_start()) { - oop old_obj = oop(r->bottom() + ShenandoahForwarding::word_size()); - size_t words_size = old_obj->size() + ShenandoahForwarding::word_size(); + oop old_obj = oop(r->bottom()); + if (!old_obj->is_forwarded()) { + // No need to move the object, it stays at the same slot + continue; + } + size_t words_size = old_obj->size(); size_t num_regions = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize); size_t old_start = r->region_number(); size_t old_end = old_start + num_regions - 1; - size_t new_start = heap->heap_region_index_containing(ShenandoahForwarding::get_forwardee_raw(old_obj)); + size_t new_start = heap->heap_region_index_containing(old_obj->forwardee()); size_t new_end = new_start + num_regions - 1; - - if (old_start == new_start) { - // No need to move the object, it stays at the same slot - continue; - } - + assert(old_start != new_start, "must be real move"); assert (r->is_move_allowed(), "should be movable"); Copy::aligned_conjoint_words(heap->get_region(old_start)->bottom(), heap->get_region(new_start)->bottom(), ShenandoahHeapRegion::region_size_words()*num_regions); - oop new_obj = oop(heap->get_region(new_start)->bottom() + ShenandoahForwarding::word_size()); - ShenandoahForwarding::initialize(new_obj); + oop new_obj = oop(heap->get_region(new_start)->bottom()); + new_obj->init_mark_raw(); { for (size_t c = old_start; c <= old_end; c++) {
--- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.hpp Thu May 30 19:51:24 2019 +0200 @@ -49,12 +49,19 @@ * where it does sliding compaction, without interfering with other threads. */ +class PreservedMarksSet; + class ShenandoahMarkCompact : public CHeapObj<mtGC> { + friend class ShenandoahPrepareForCompactionObjectClosure; private: GCTimer* _gc_timer; + PreservedMarksSet* _preserved_marks; + public: + ShenandoahMarkCompact(); void initialize(GCTimer* gc_timer); + void do_it(GCCause::Cause gc_cause); private: @@ -65,7 +72,6 @@ void calculate_target_humongous_objects(); void compact_humongous_objects(); - }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARKCOMPACT_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp Thu May 30 19:51:24 2019 +0200 @@ -27,6 +27,7 @@ #include "gc/shenandoah/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahRootProcessor.hpp" #include "gc/shenandoah/shenandoahTimingTracker.hpp" +#include "gc/shenandoah/shenandoahUtils.hpp" #include "memory/resourceArea.hpp" template <typename IsAlive, typename KeepAlive> @@ -90,9 +91,10 @@ template <typename ITR> void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure *tc) { - assert(!ShenandoahHeap::heap()->unload_classes() || + assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint() || + !ShenandoahHeap::heap()->unload_classes() || ShenandoahHeap::heap()->heuristics()->can_do_traversal_gc(), - "No class unloading or traversal GC"); + "Expect class unloading or traversal when Shenandoah cycle is running"); ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc); ResourceMark rm;
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp Thu May 30 19:51:24 2019 +0200 @@ -59,7 +59,7 @@ } if (verify(CLDGRoots)) { - CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong); + CLDToOopClosure clds(oops, ClassLoaderData::_claim_none); ClassLoaderDataGraph::cld_do(&clds); } @@ -88,3 +88,49 @@ Threads::possibly_parallel_oops_do(false, oops, &blobs); } } + +void ShenandoahRootVerifier::roots_do(OopClosure* oops) { + CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); + CodeCache::blobs_do(&blobs); + + CLDToOopClosure clds(oops, ClassLoaderData::_claim_none); + ClassLoaderDataGraph::cld_do(&clds); + + Universe::oops_do(oops); + Management::oops_do(oops); + JvmtiExport::oops_do(oops); + JNIHandles::oops_do(oops); + ObjectSynchronizer::oops_do(oops); + SystemDictionary::oops_do(oops); + + AlwaysTrueClosure always_true; + WeakProcessor::weak_oops_do(&always_true, oops); + + if (ShenandoahStringDedup::is_enabled()) { + ShenandoahStringDedup::oops_do_slow(oops); + } + + // Do thread roots the last. This allows verification code to find + // any broken objects from those special roots first, not the accidental + // dangling reference from the thread root. + Threads::possibly_parallel_oops_do(false, oops, &blobs); +} + +void ShenandoahRootVerifier::strong_roots_do(OopClosure* oops) { + CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); + + CLDToOopClosure clds(oops, ClassLoaderData::_claim_none); + ClassLoaderDataGraph::roots_cld_do(&clds, NULL); + + Universe::oops_do(oops); + Management::oops_do(oops); + JvmtiExport::oops_do(oops); + JNIHandles::oops_do(oops); + ObjectSynchronizer::oops_do(oops); + SystemDictionary::oops_do(oops); + + // Do thread roots the last. This allows verification code to find + // any broken objects from those special roots first, not the accidental + // dangling reference from the thread root. + Threads::possibly_parallel_oops_do(false, oops, &blobs); +}
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp Thu May 30 19:51:24 2019 +0200 @@ -48,6 +48,9 @@ void excludes(RootTypes types); void oops_do(OopClosure* cl); + // Used to seed ShenandoahVerifier, do not honor root type filter + void roots_do(OopClosure* cl); + void strong_roots_do(OopClosure* cl); private: bool verify(RootTypes type) const; };
--- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp Thu May 30 19:51:24 2019 +0200 @@ -35,7 +35,6 @@ #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" -#include "gc/shenandoah/shenandoahForwarding.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegionSet.inline.hpp" @@ -633,7 +632,7 @@ bool candidate = traversal_regions->is_in(r) && !r->has_live() && not_allocated; if (r->is_humongous_start() && candidate) { // Trash humongous. - HeapWord* humongous_obj = r->bottom() + ShenandoahForwarding::word_size(); + HeapWord* humongous_obj = r->bottom(); assert(!ctx->is_marked(oop(humongous_obj)), "must not be marked"); r->make_trash_immediate(); while (i + 1 < num_regions && _heap->get_region(i + 1)->is_humongous_continuation()) {
--- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp Thu May 30 19:51:24 2019 +0200 @@ -138,7 +138,7 @@ // skip break; case ShenandoahVerifier::_verify_liveness_complete: - Atomic::add(obj->size() + ShenandoahForwarding::word_size(), &_ld[obj_reg->region_number()]); + Atomic::add((uint) obj->size(), &_ld[obj_reg->region_number()]); // fallthrough for fast failure for un-live regions: case ShenandoahVerifier::_verify_liveness_conservative: check(ShenandoahAsserts::_safe_oop, obj, obj_reg->has_live(), @@ -458,7 +458,11 @@ ShenandoahVerifyOopClosure cl(&stack, _bitmap, _ld, ShenandoahMessageBuffer("%s, Roots", _label), _options); - _verifier->oops_do(&cl); + if (_heap->unload_classes()) { + _verifier->strong_roots_do(&cl); + } else { + _verifier->roots_do(&cl); + } } size_t processed = 0; @@ -529,7 +533,7 @@ virtual void work_humongous(ShenandoahHeapRegion *r, ShenandoahVerifierStack& stack, ShenandoahVerifyOopClosure& cl) { size_t processed = 0; - HeapWord* obj = r->bottom() + ShenandoahForwarding::word_size(); + HeapWord* obj = r->bottom(); if (_heap->complete_marking_context()->is_marked((oop)obj)) { verify_and_follow(obj, stack, cl, &processed); } @@ -543,12 +547,12 @@ // Bitmaps, before TAMS if (tams > r->bottom()) { - HeapWord* start = r->bottom() + ShenandoahForwarding::word_size(); + HeapWord* start = r->bottom(); HeapWord* addr = mark_bit_map->get_next_marked_addr(start, tams); while (addr < tams) { verify_and_follow(addr, stack, cl, &processed); - addr += ShenandoahForwarding::word_size(); + addr += 1; if (addr < tams) { addr = mark_bit_map->get_next_marked_addr(addr, tams); } @@ -558,11 +562,11 @@ // Size-based, after TAMS { HeapWord* limit = r->top(); - HeapWord* addr = tams + ShenandoahForwarding::word_size(); + HeapWord* addr = tams; while (addr < limit) { verify_and_follow(addr, stack, cl, &processed); - addr += oop(addr)->size() + ShenandoahForwarding::word_size(); + addr += oop(addr)->size(); } }
--- a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp Thu May 30 19:51:24 2019 +0200 @@ -67,9 +67,14 @@ private: CPUInformationInterface* _cpu_info_interface; CPUPerformanceInterface* _cpu_perf_interface; - SystemProcessInterface* _system_process_interface; + SystemProcessInterface* _system_process_interface; NetworkPerformanceInterface* _network_performance_interface; + CPUInformationInterface* cpu_info_interface(); + CPUPerformanceInterface* cpu_perf_interface(); + SystemProcessInterface* system_process_interface(); + NetworkPerformanceInterface* network_performance_interface(); + JfrOSInterfaceImpl(); bool initialize(); ~JfrOSInterfaceImpl(); @@ -90,28 +95,57 @@ // system processes information int system_processes(SystemProcess** system_processes, int* no_of_sys_processes); - int network_utilization(NetworkInterface** network_interfaces) const; + int network_utilization(NetworkInterface** network_interfaces); }; JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(NULL), _cpu_perf_interface(NULL), - _system_process_interface(NULL) {} + _system_process_interface(NULL), + _network_performance_interface(NULL) {} + +template <typename T> +static T* create_interface() { + ResourceMark rm; + T* iface = new T(); + if (iface != NULL) { + if (!iface->initialize()) { + delete iface; + iface = NULL; + } + } + return iface; +} + +CPUInformationInterface* JfrOSInterface::JfrOSInterfaceImpl::cpu_info_interface() { + if (_cpu_info_interface == NULL) { + _cpu_info_interface = create_interface<CPUInformationInterface>(); + } + return _cpu_info_interface; +} + +CPUPerformanceInterface* JfrOSInterface::JfrOSInterfaceImpl::cpu_perf_interface() { + if (_cpu_perf_interface == NULL) { + _cpu_perf_interface = create_interface<CPUPerformanceInterface>(); + } + return _cpu_perf_interface; +} + +SystemProcessInterface* JfrOSInterface::JfrOSInterfaceImpl::system_process_interface() { + if (_system_process_interface == NULL) { + _system_process_interface = create_interface<SystemProcessInterface>(); + } + return _system_process_interface; +} + +NetworkPerformanceInterface* JfrOSInterface::JfrOSInterfaceImpl::network_performance_interface() { + if (_network_performance_interface == NULL) { + _network_performance_interface = create_interface<NetworkPerformanceInterface>(); + } + return _network_performance_interface; +} bool JfrOSInterface::JfrOSInterfaceImpl::initialize() { - _cpu_info_interface = new CPUInformationInterface(); - if (!(_cpu_info_interface != NULL && _cpu_info_interface->initialize())) { - return false; - } - _cpu_perf_interface = new CPUPerformanceInterface(); - if (!(_cpu_perf_interface != NULL && _cpu_perf_interface->initialize())) { - return false; - } - _system_process_interface = new SystemProcessInterface(); - if (!(_system_process_interface != NULL && _system_process_interface->initialize())) { - return false; - } - _network_performance_interface = new NetworkPerformanceInterface(); - return _network_performance_interface != NULL && _network_performance_interface->initialize(); + return true; } JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) { @@ -133,36 +167,43 @@ } } +int JfrOSInterface::JfrOSInterfaceImpl::cpu_information(CPUInformation& cpu_info) { + CPUInformationInterface* const iface = cpu_info_interface(); + return iface == NULL ? OS_ERR : iface->cpu_information(cpu_info); +} + int JfrOSInterface::JfrOSInterfaceImpl::cpu_load(int which_logical_cpu, double* cpu_load) { - return _cpu_perf_interface->cpu_load(which_logical_cpu, cpu_load); + CPUPerformanceInterface* const iface = cpu_perf_interface(); + return iface == NULL ? OS_ERR : iface->cpu_load(which_logical_cpu, cpu_load); } int JfrOSInterface::JfrOSInterfaceImpl::context_switch_rate(double* rate) { - return _cpu_perf_interface->context_switch_rate(rate); + CPUPerformanceInterface* const iface = cpu_perf_interface(); + return iface == NULL ? OS_ERR : iface->context_switch_rate(rate); } int JfrOSInterface::JfrOSInterfaceImpl::cpu_load_total_process(double* cpu_load) { - return _cpu_perf_interface->cpu_load_total_process(cpu_load); + CPUPerformanceInterface* const iface = cpu_perf_interface(); + return iface == NULL ? OS_ERR : iface->cpu_load_total_process(cpu_load); } int JfrOSInterface::JfrOSInterfaceImpl::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotal) { - return _cpu_perf_interface->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotal); -} - -int JfrOSInterface::JfrOSInterfaceImpl::cpu_information(CPUInformation& cpu_info) { - return _cpu_info_interface->cpu_information(cpu_info); + CPUPerformanceInterface* const iface = cpu_perf_interface(); + return iface == NULL ? OS_ERR : iface->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotal); } int JfrOSInterface::JfrOSInterfaceImpl::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) { assert(system_processes != NULL, "system_processes pointer is NULL!"); assert(no_of_sys_processes != NULL, "no_of_sys_processes pointer is NULL!"); - return _system_process_interface->system_processes(system_processes, no_of_sys_processes); + SystemProcessInterface* const iface = system_process_interface(); + return iface == NULL ? OS_ERR : iface->system_processes(system_processes, no_of_sys_processes); } -int JfrOSInterface::JfrOSInterfaceImpl::network_utilization(NetworkInterface** network_interfaces) const { - return _network_performance_interface->network_utilization(network_interfaces); +int JfrOSInterface::JfrOSInterfaceImpl::network_utilization(NetworkInterface** network_interfaces) { + NetworkPerformanceInterface* const iface = network_performance_interface(); + return iface == NULL ? OS_ERR : iface->network_utilization(network_interfaces); } // assigned char* is RESOURCE_HEAP_ALLOCATED
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.cpp Thu May 30 19:51:24 2019 +0200 @@ -132,10 +132,6 @@ OrderAccess::release_store(&_identity, (const void*)NULL); } -void JfrBuffer::clear_identity() { - _identity = NULL; -} - bool JfrBuffer::acquired_by(const void* id) const { return identity() == id; }
--- a/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/storage/jfrBuffer.hpp Thu May 30 19:51:24 2019 +0200 @@ -145,8 +145,6 @@ return _identity; } - void clear_identity(); - void acquire(const void* id); bool try_acquire(const void* id); bool acquired_by(const void* id) const;
--- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp Thu May 30 19:51:24 2019 +0200 @@ -312,7 +312,11 @@ static bool insert_full_age_node(JfrAgeNode* age_node, JfrStorageAgeMspace* age_mspace, Thread* thread) { assert(JfrBuffer_lock->owned_by_self(), "invariant"); + assert(age_node != NULL, "invariant"); + assert(age_node->acquired_by_self(), "invariant"); assert(age_node->retired_buffer()->retired(), "invariant"); + age_node->release(); // drop identity claim on age node when inserting to full list + assert(age_node->identity() == NULL, "invariant"); age_mspace->insert_full_head(age_node); return true; } @@ -329,8 +333,8 @@ return false; } } + assert(age_node != NULL, "invariant"); assert(age_node->acquired_by_self(), "invariant"); - assert(age_node != NULL, "invariant"); age_node->set_retired_buffer(buffer); control.increment_full(); return insert_full_age_node(age_node, age_mspace, thread); @@ -412,6 +416,7 @@ if (oldest_age_node == NULL) { break; } + assert(oldest_age_node->identity() == NULL, "invariant"); BufferPtr const buffer = oldest_age_node->retired_buffer(); assert(buffer->retired(), "invariant"); discarded_size += buffer->unflushed_size(); @@ -423,7 +428,7 @@ } else { mspace_release_full(oldest_age_node, _age_mspace); buffer->reinitialize(); - buffer->release(); // pusb + buffer->release(); // publish break; } } @@ -637,12 +642,12 @@ JfrAgeNode* last = NULL; while (node != NULL) { last = node; + assert(node->identity() == NULL, "invariant"); BufferPtr const buffer = node->retired_buffer(); assert(buffer != NULL, "invariant"); assert(buffer->retired(), "invariant"); processor.process(buffer); // at this point, buffer is already live or destroyed - node->clear_identity(); JfrAgeNode* const next = (JfrAgeNode*)node->next(); if (node->transient()) { // detach
--- a/src/hotspot/share/jfr/support/jfrFlush.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/jfr/support/jfrFlush.cpp Thu May 30 19:51:24 2019 +0200 @@ -62,7 +62,6 @@ } void jfr_conditional_flush(JfrEventId id, size_t size, Thread* t) { - assert(jfr_is_event_enabled(id), "invariant"); if (t->jfr_thread_local()->has_native_buffer()) { JfrStorage::Buffer* const buffer = t->jfr_thread_local()->native_buffer(); if (LessThanSize<JfrStorage::Buffer>::evaluate(buffer, size)) {
--- a/src/hotspot/share/oops/cpCache.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/oops/cpCache.cpp Thu May 30 19:51:24 2019 +0200 @@ -261,11 +261,22 @@ method->name() != vmSymbols::object_initializer_name()) { do_resolve = false; } - // Don't mark invokestatic to method as resolved if the holder class has not yet completed - // initialization. An invokestatic must only proceed if the class is initialized, but if - // we resolve it before then that class initialization check is skipped. - if (invoke_code == Bytecodes::_invokestatic && !method->method_holder()->is_initialized()) { - do_resolve = false; + if (invoke_code == Bytecodes::_invokestatic) { + assert(method->method_holder()->is_initialized() || + method->method_holder()->is_reentrant_initialization(Thread::current()), + "invalid class initialization state for invoke_static"); + + if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + // Don't mark invokestatic to method as resolved if the holder class has not yet completed + // initialization. An invokestatic must only proceed if the class is initialized, but if + // we resolve it before then that class initialization check is skipped. + // + // When fast class initialization checks are supported (VM_Version::supports_fast_class_init_checks() == true), + // template interpreter supports fast class initialization check for + // invokestatic which doesn't require call site re-resolution to + // enforce class initialization barrier. + do_resolve = false; + } } if (do_resolve) { set_bytecode_1(invoke_code);
--- a/src/hotspot/share/oops/method.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/oops/method.cpp Thu May 30 19:51:24 2019 +0200 @@ -704,6 +704,10 @@ return name() == vmSymbols::object_initializer_name(); } +bool Method::needs_clinit_barrier() const { + return is_static() && !method_holder()->is_initialized(); +} + objArrayHandle Method::resolved_checked_exceptions_impl(Method* method, TRAPS) { int length = method->checked_exceptions_length(); if (length == 0) { // common case
--- a/src/hotspot/share/oops/method.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/oops/method.hpp Thu May 30 19:51:24 2019 +0200 @@ -699,6 +699,8 @@ bool has_aot_code() const { return aot_code() != NULL; } #endif + bool needs_clinit_barrier() const; + // sizing static int header_size() { return align_up((int)sizeof(Method), wordSize) / wordSize;
--- a/src/hotspot/share/oops/methodData.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/oops/methodData.hpp Thu May 30 19:51:24 2019 +0200 @@ -2012,7 +2012,7 @@ // Whole-method sticky bits and flags enum { - _trap_hist_limit = 24 JVMCI_ONLY(+5), // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 25 JVMCI_ONLY(+5), // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values
--- a/src/hotspot/share/opto/bytecodeInfo.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/bytecodeInfo.cpp Thu May 30 19:51:24 2019 +0200 @@ -202,15 +202,15 @@ const char* fail_msg = NULL; // First check all inlining restrictions which are required for correctness - if ( callee_method->is_abstract()) { + if (callee_method->is_abstract()) { fail_msg = "abstract method"; // // note: we allow ik->is_abstract() } else if (!callee_method->holder()->is_initialized() && // access allowed in the context of static initializer - !C->is_compiling_clinit_for(callee_method->holder())) { + C->needs_clinit_barrier(callee_method->holder(), caller_method)) { fail_msg = "method holder not initialized"; - } else if ( callee_method->is_native()) { + } else if (callee_method->is_native()) { fail_msg = "native method"; - } else if ( callee_method->dont_inline()) { + } else if (callee_method->dont_inline()) { fail_msg = "don't inline by annotation"; } @@ -478,14 +478,18 @@ //------------------------------pass_initial_checks---------------------------- bool InlineTree::pass_initial_checks(ciMethod* caller_method, int caller_bci, ciMethod* callee_method) { - ciInstanceKlass *callee_holder = callee_method ? callee_method->holder() : NULL; // Check if a callee_method was suggested - if( callee_method == NULL ) return false; + if (callee_method == NULL) { + return false; + } + ciInstanceKlass *callee_holder = callee_method->holder(); // Check if klass of callee_method is loaded - if( !callee_holder->is_loaded() ) return false; - if( !callee_holder->is_initialized() && + if (!callee_holder->is_loaded()) { + return false; + } + if (!callee_holder->is_initialized() && // access allowed in the context of static initializer - !C->is_compiling_clinit_for(callee_holder)) { + C->needs_clinit_barrier(callee_holder, caller_method)) { return false; } if( !UseInterpreter ) /* running Xcomp */ {
--- a/src/hotspot/share/opto/compile.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/compile.cpp Thu May 30 19:51:24 2019 +0200 @@ -654,6 +654,7 @@ _trace_opto_output(directive->TraceOptoOutputOption), #endif _has_method_handle_invokes(false), + _clinit_barrier_on_entry(false), _comp_arena(mtCompiler), _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), _env(ci_env), @@ -988,6 +989,7 @@ _trace_opto_output(directive->TraceOptoOutputOption), #endif _has_method_handle_invokes(false), + _clinit_barrier_on_entry(false), _comp_arena(mtCompiler), _env(ci_env), _directive(directive), @@ -1170,6 +1172,9 @@ } } #endif + if (VM_Version::supports_fast_class_init_checks() && has_method() && !is_osr_compilation() && method()->needs_clinit_barrier()) { + set_clinit_barrier_on_entry(true); + } if (debug_info()->recording_non_safepoints()) { set_node_note_array(new(comp_arena()) GrowableArray<Node_Notes*> (comp_arena(), 8, 0, NULL)); @@ -3841,9 +3846,42 @@ } } -bool Compile::is_compiling_clinit_for(ciKlass* k) { - ciMethod* root = method(); // the root method of compilation - return root->is_static_initializer() && root->holder() == k; // access in the context of clinit +bool Compile::needs_clinit_barrier(ciMethod* method, ciMethod* accessing_method) { + return method->is_static() && needs_clinit_barrier(method->holder(), accessing_method); +} + +bool Compile::needs_clinit_barrier(ciField* field, ciMethod* accessing_method) { + return field->is_static() && needs_clinit_barrier(field->holder(), accessing_method); +} + +bool Compile::needs_clinit_barrier(ciInstanceKlass* holder, ciMethod* accessing_method) { + if (holder->is_initialized()) { + return false; + } + if (holder->is_being_initialized()) { + if (accessing_method->holder() == holder) { + // Access inside a class. The barrier can be elided when access happens in <clinit>, + // <init>, or a static method. In all those cases, there was an initialization + // barrier on the holder klass passed. + if (accessing_method->is_static_initializer() || + accessing_method->is_object_initializer() || + accessing_method->is_static()) { + return false; + } + } else if (accessing_method->holder()->is_subclass_of(holder)) { + // Access from a subclass. The barrier can be elided only when access happens in <clinit>. + // In case of <init> or a static method, the barrier is on the subclass is not enough: + // child class can become fully initialized while its parent class is still being initialized. + if (accessing_method->is_static_initializer()) { + return false; + } + } + ciMethod* root = method(); // the root method of compilation + if (root != accessing_method) { + return needs_clinit_barrier(holder, root); // check access in the context of compilation root + } + } + return true; } #ifndef PRODUCT
--- a/src/hotspot/share/opto/compile.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/compile.hpp Thu May 30 19:51:24 2019 +0200 @@ -416,6 +416,7 @@ bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. RTMState _rtm_state; // State of Restricted Transactional Memory usage int _loop_opts_cnt; // loop opts round + bool _clinit_barrier_on_entry; // True if clinit barrier is needed on nmethod entry // Compilation environment. Arena _comp_arena; // Arena with lifetime equivalent to Compile @@ -714,6 +715,8 @@ bool profile_rtm() const { return _rtm_state == ProfileRTM; } uint max_node_limit() const { return (uint)_max_node_limit; } void set_max_node_limit(uint n) { _max_node_limit = n; } + bool clinit_barrier_on_entry() { return _clinit_barrier_on_entry; } + void set_clinit_barrier_on_entry(bool z) { _clinit_barrier_on_entry = z; } // check the CompilerOracle for special behaviours for this compile bool method_has_option(const char * option) { @@ -1381,7 +1384,9 @@ CloneMap& clone_map(); void set_clone_map(Dict* d); - bool is_compiling_clinit_for(ciKlass* k); + bool needs_clinit_barrier(ciField* ik, ciMethod* accessing_method); + bool needs_clinit_barrier(ciMethod* ik, ciMethod* accessing_method); + bool needs_clinit_barrier(ciInstanceKlass* ik, ciMethod* accessing_method); }; #endif // SHARE_OPTO_COMPILE_HPP
--- a/src/hotspot/share/opto/graphKit.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/graphKit.cpp Thu May 30 19:51:24 2019 +0200 @@ -2854,6 +2854,60 @@ return false; } +void GraphKit::guard_klass_being_initialized(Node* klass) { + int init_state_off = in_bytes(InstanceKlass::init_state_offset()); + Node* adr = basic_plus_adr(top(), klass, init_state_off); + Node* init_state = LoadNode::make(_gvn, NULL, immutable_memory(), adr, + adr->bottom_type()->is_ptr(), TypeInt::BYTE, + T_BYTE, MemNode::unordered); + init_state = _gvn.transform(init_state); + + Node* being_initialized_state = makecon(TypeInt::make(InstanceKlass::being_initialized)); + + Node* chk = _gvn.transform(new CmpINode(being_initialized_state, init_state)); + Node* tst = _gvn.transform(new BoolNode(chk, BoolTest::eq)); + + { BuildCutout unless(this, tst, PROB_MAX); + uncommon_trap(Deoptimization::Reason_initialized, Deoptimization::Action_reinterpret); + } +} + +void GraphKit::guard_init_thread(Node* klass) { + int init_thread_off = in_bytes(InstanceKlass::init_thread_offset()); + Node* adr = basic_plus_adr(top(), klass, init_thread_off); + + Node* init_thread = LoadNode::make(_gvn, NULL, immutable_memory(), adr, + adr->bottom_type()->is_ptr(), TypePtr::NOTNULL, + T_ADDRESS, MemNode::unordered); + init_thread = _gvn.transform(init_thread); + + Node* cur_thread = _gvn.transform(new ThreadLocalNode()); + + Node* chk = _gvn.transform(new CmpPNode(cur_thread, init_thread)); + Node* tst = _gvn.transform(new BoolNode(chk, BoolTest::eq)); + + { BuildCutout unless(this, tst, PROB_MAX); + uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_none); + } +} + +void GraphKit::clinit_barrier(ciInstanceKlass* ik, ciMethod* context) { + if (ik->is_being_initialized()) { + if (C->needs_clinit_barrier(ik, context)) { + Node* klass = makecon(TypeKlassPtr::make(ik)); + guard_klass_being_initialized(klass); + guard_init_thread(klass); + insert_mem_bar(Op_MemBarCPUOrder); + } + } else if (ik->is_initialized()) { + return; // no barrier needed + } else { + uncommon_trap(Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret, + NULL); + } +} + //------------------------maybe_cast_profiled_receiver------------------------- // If the profile has seen exactly one type, narrow to exactly that type. // Subsequent type checks will always fold up.
--- a/src/hotspot/share/opto/graphKit.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/graphKit.hpp Thu May 30 19:51:24 2019 +0200 @@ -386,6 +386,11 @@ // Check the null_seen bit. bool seems_never_null(Node* obj, ciProfileData* data, bool& speculating); + void guard_klass_being_initialized(Node* klass); + void guard_init_thread(Node* klass); + + void clinit_barrier(ciInstanceKlass* ik, ciMethod* context); + // Check for unique class for receiver at call ciKlass* profile_has_unique_klass() { ciCallProfile profile = method()->call_profile_at_bci(bci());
--- a/src/hotspot/share/opto/machnode.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/machnode.hpp Thu May 30 19:51:24 2019 +0200 @@ -301,7 +301,14 @@ // Bottom_type call; value comes from operand0 virtual const class Type *bottom_type() const { return _opnds[0]->type(); } - virtual uint ideal_reg() const { const Type *t = _opnds[0]->type(); return t == TypeInt::CC ? Op_RegFlags : t->ideal_reg(); } + virtual uint ideal_reg() const { + const Type *t = _opnds[0]->type(); + if (t == TypeInt::CC) { + return Op_RegFlags; + } else { + return t->ideal_reg(); + } + } // If this is a memory op, return the base pointer and fixed offset. // If there are no such, return NULL. If there are multiple addresses
--- a/src/hotspot/share/opto/node.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/node.hpp Thu May 30 19:51:24 2019 +0200 @@ -998,7 +998,7 @@ // the node is guaranteed never to compare equal to any other node. // If we accidentally generate a hash with value NO_HASH the node // won't go into the table and we'll lose a little optimization. - enum { NO_HASH = 0 }; + static const uint NO_HASH = 0; virtual uint hash() const; virtual bool cmp( const Node &n ) const;
--- a/src/hotspot/share/opto/parse.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/parse.hpp Thu May 30 19:51:24 2019 +0200 @@ -482,6 +482,8 @@ // Helper function to compute array addressing Node* array_addressing(BasicType type, int vals, const Type* *result2=NULL); + void clinit_deopt(); + void rtm_deopt(); // Pass current map to exits @@ -530,14 +532,12 @@ // common code for making initial checks and forming addresses void do_field_access(bool is_get, bool is_field); - bool static_field_ok_in_clinit(ciField *field, ciMethod *method); // common code for actually performing the load or store void do_get_xxx(Node* obj, ciField* field, bool is_field); void do_put_xxx(Node* obj, ciField* field, bool is_field); // implementation of object creation bytecodes - void emit_guard_for_new(ciInstanceKlass* klass); void do_new(); void do_newarray(BasicType elemtype); void do_anewarray();
--- a/src/hotspot/share/opto/parse1.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/parse1.cpp Thu May 30 19:51:24 2019 +0200 @@ -584,6 +584,11 @@ } if (depth() == 1 && !failing()) { + if (C->clinit_barrier_on_entry()) { + // Add check to deoptimize the nmethod once the holder class is fully initialized + clinit_deopt(); + } + // Add check to deoptimize the nmethod if RTM state was changed rtm_deopt(); } @@ -1192,7 +1197,7 @@ // The main thing to do is lock the receiver of a synchronized method. void Parse::do_method_entry() { set_parse_bci(InvocationEntryBci); // Pseudo-BCP - set_sp(0); // Java Stack Pointer + set_sp(0); // Java Stack Pointer NOT_PRODUCT( count_compiled_calls(true/*at_method_entry*/, false/*is_inline*/); ) @@ -2102,11 +2107,25 @@ set_control( _gvn.transform(result_rgn) ); } +// Add check to deoptimize once holder klass is fully initialized. +void Parse::clinit_deopt() { + assert(C->has_method(), "only for normal compilations"); + assert(depth() == 1, "only for main compiled method"); + assert(is_normal_parse(), "no barrier needed on osr entry"); + assert(method()->holder()->is_being_initialized() || method()->holder()->is_initialized(), + "initialization should have been started"); + + set_parse_bci(0); + + Node* holder = makecon(TypeKlassPtr::make(method()->holder())); + guard_klass_being_initialized(holder); +} + // Add check to deoptimize if RTM state is not ProfileRTM void Parse::rtm_deopt() { #if INCLUDE_RTM_OPT if (C->profile_rtm()) { - assert(C->method() != NULL, "only for normal compilations"); + assert(C->has_method(), "only for normal compilations"); assert(!C->method()->method_data()->is_empty(), "MDO is needed to record RTM state"); assert(depth() == 1, "generate check only for main compiled method");
--- a/src/hotspot/share/opto/parse3.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/parse3.cpp Thu May 30 19:51:24 2019 +0200 @@ -40,39 +40,6 @@ //============================================================================= // Helper methods for _get* and _put* bytecodes //============================================================================= -bool Parse::static_field_ok_in_clinit(ciField *field, ciMethod *method) { - // Could be the field_holder's <clinit> method, or <clinit> for a subklass. - // Better to check now than to Deoptimize as soon as we execute - assert( field->is_static(), "Only check if field is static"); - // is_being_initialized() is too generous. It allows access to statics - // by threads that are not running the <clinit> before the <clinit> finishes. - // return field->holder()->is_being_initialized(); - - // The following restriction is correct but conservative. - // It is also desirable to allow compilation of methods called from <clinit> - // but this generated code will need to be made safe for execution by - // other threads, or the transition from interpreted to compiled code would - // need to be guarded. - ciInstanceKlass *field_holder = field->holder(); - - if (method->holder()->is_subclass_of(field_holder)) { - if (method->is_static_initializer()) { - // OK to access static fields inside initializer - return true; - } else if (method->is_object_initializer()) { - // It's also OK to access static fields inside a constructor, - // because any thread calling the constructor must first have - // synchronized on the class by executing a '_new' bytecode. - return true; - } - } - if (C->is_compiling_clinit_for(field_holder)) { - return true; // access in the context of static initializer - } - return false; -} - - void Parse::do_field_access(bool is_get, bool is_field) { bool will_link; ciField* field = iter().get_field(will_link); @@ -88,15 +55,6 @@ return; } - if (!is_field && !field_holder->is_initialized()) { - if (!static_field_ok_in_clinit(field, method())) { - uncommon_trap(Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret, - NULL, "!static_field_ok_in_clinit"); - return; - } - } - // Deoptimize on putfield writes to call site target field. if (!is_get && field->is_call_site_target()) { uncommon_trap(Deoptimization::Reason_unhandled, @@ -105,6 +63,11 @@ return; } + if (C->needs_clinit_barrier(field, method())) { + clinit_barrier(field_holder, method()); + if (stopped()) return; + } + assert(field->will_link(method(), bc()), "getfield: typeflow responsibility"); // Note: We do not check for an unloaded field type here any more.
--- a/src/hotspot/share/opto/parseHelper.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/opto/parseHelper.cpp Thu May 30 19:51:24 2019 +0200 @@ -235,45 +235,6 @@ } -void Parse::emit_guard_for_new(ciInstanceKlass* klass) { - // Emit guarded new - // if (klass->_init_thread != current_thread || - // klass->_init_state != being_initialized) - // uncommon_trap - Node* cur_thread = _gvn.transform( new ThreadLocalNode() ); - Node* merge = new RegionNode(3); - _gvn.set_type(merge, Type::CONTROL); - Node* kls = makecon(TypeKlassPtr::make(klass)); - - Node* init_thread_offset = _gvn.MakeConX(in_bytes(InstanceKlass::init_thread_offset())); - Node* adr_node = basic_plus_adr(kls, kls, init_thread_offset); - Node* init_thread = make_load(NULL, adr_node, TypeRawPtr::BOTTOM, T_ADDRESS, MemNode::unordered); - Node *tst = Bool( CmpP( init_thread, cur_thread), BoolTest::eq); - IfNode* iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN); - set_control(IfTrue(iff)); - merge->set_req(1, IfFalse(iff)); - - Node* init_state_offset = _gvn.MakeConX(in_bytes(InstanceKlass::init_state_offset())); - adr_node = basic_plus_adr(kls, kls, init_state_offset); - // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler - // can generate code to load it as unsigned byte. - Node* init_state = make_load(NULL, adr_node, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered); - Node* being_init = _gvn.intcon(InstanceKlass::being_initialized); - tst = Bool( CmpI( init_state, being_init), BoolTest::eq); - iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN); - set_control(IfTrue(iff)); - merge->set_req(2, IfFalse(iff)); - - PreserveJVMState pjvms(this); - record_for_igvn(merge); - set_control(merge); - - uncommon_trap(Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret, - klass); -} - - //------------------------------do_new----------------------------------------- void Parse::do_new() { kill_dead_locals(); @@ -282,18 +243,19 @@ ciInstanceKlass* klass = iter().get_klass(will_link)->as_instance_klass(); assert(will_link, "_new: typeflow responsibility"); - // Should initialize, or throw an InstantiationError? - if ((!klass->is_initialized() && !klass->is_being_initialized()) || - klass->is_abstract() || klass->is_interface() || + // Should throw an InstantiationError? + if (klass->is_abstract() || klass->is_interface() || klass->name() == ciSymbol::java_lang_Class() || iter().is_unresolved_klass()) { - uncommon_trap(Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret, + uncommon_trap(Deoptimization::Reason_unhandled, + Deoptimization::Action_none, klass); return; } - if (klass->is_being_initialized()) { - emit_guard_for_new(klass); + + if (C->needs_clinit_barrier(klass, method())) { + clinit_barrier(klass, method()); + if (stopped()) return; } Node* kls = makecon(TypeKlassPtr::make(klass));
--- a/src/hotspot/share/prims/jvmti.xml Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/prims/jvmti.xml Thu May 30 19:51:24 2019 +0200 @@ -7437,7 +7437,7 @@ <capabilities> <capability id="can_redefine_any_class"> If possessed then all classes (except primitive, array, and some implementation defined - classes) are modifiable (redefine or retransform). + classes) are modifiable with <functionlink id="RedefineClasses"/>. </capability> <capability id="can_retransform_any_class"> If possessed then all classes (except primitive, array, and some implementation defined @@ -10199,8 +10199,10 @@ </capabilityfield> <capabilityfield id="can_redefine_any_class"> <description> - Can modify (retransform or redefine) any modifiable class. + <functionlink id="RedefineClasses"/> can be called on any modifiable class. See <functionlink id="IsModifiableClass"/>. + (<fieldlink id="can_redefine_classes" struct="jvmtiCapabilities"/> + must also be set) </description> </capabilityfield> <capabilityfield id="can_get_current_thread_cpu_time"> @@ -14957,6 +14959,12 @@ - Add new error JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED that can be returned by RedefineClasses and RetransformClasses. </change> + <change date="20 May 2019" version="13.0.0"> + Minor spec update for the capability "can_redefine_any_class". + It now says: + "RedefineClasses can be called on any modifiable class. See IsModifiableClass. + (can_redefine_classes must also be set)" + </change> </changehistory> </specification>
--- a/src/hotspot/share/runtime/arguments.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/runtime/arguments.cpp Thu May 30 19:51:24 2019 +0200 @@ -1722,9 +1722,33 @@ static const size_t DefaultHeapBaseMinAddress = HeapBaseMinAddress; void Arguments::set_heap_size() { - julong phys_mem = - FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM) - : (julong)MaxRAM; + julong phys_mem; + + // If the user specified one of these options, they + // want specific memory sizing so do not limit memory + // based on compressed oops addressability. + // Also, memory limits will be calculated based on + // available os physical memory, not our MaxRAM limit, + // unless MaxRAM is also specified. + bool override_coop_limit = (!FLAG_IS_DEFAULT(MaxRAMPercentage) || + !FLAG_IS_DEFAULT(MaxRAMFraction) || + !FLAG_IS_DEFAULT(MinRAMPercentage) || + !FLAG_IS_DEFAULT(MinRAMFraction) || + !FLAG_IS_DEFAULT(InitialRAMPercentage) || + !FLAG_IS_DEFAULT(InitialRAMFraction) || + !FLAG_IS_DEFAULT(MaxRAM)); + if (override_coop_limit) { + if (FLAG_IS_DEFAULT(MaxRAM)) { + phys_mem = os::physical_memory(); + FLAG_SET_ERGO(MaxRAM, (uint64_t)phys_mem); + } else { + phys_mem = (julong)MaxRAM; + } + } else { + phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM) + : (julong)MaxRAM; + } + // Convert deprecated flags if (FLAG_IS_DEFAULT(MaxRAMPercentage) && @@ -1780,7 +1804,19 @@ // but it should be not less than default MaxHeapSize. max_coop_heap -= HeapBaseMinAddress; } - reasonable_max = MIN2(reasonable_max, max_coop_heap); + + // If user specified flags prioritizing os physical + // memory limits, then disable compressed oops if + // limits exceed max_coop_heap and UseCompressedOops + // was not specified. + if (reasonable_max > max_coop_heap) { + if (FLAG_IS_ERGO(UseCompressedOops) && override_coop_limit) { + FLAG_SET_ERGO(UseCompressedOops, false); + FLAG_SET_ERGO(UseCompressedClassPointers, false); + } else { + reasonable_max = MIN2(reasonable_max, max_coop_heap); + } + } } reasonable_max = limit_by_allocatable_memory(reasonable_max);
--- a/src/hotspot/share/runtime/deoptimization.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/runtime/deoptimization.cpp Thu May 30 19:51:24 2019 +0200 @@ -2176,6 +2176,7 @@ "profile_predicate", "unloaded", "uninitialized", + "initialized", "unreached", "unhandled", "constraint",
--- a/src/hotspot/share/runtime/deoptimization.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/runtime/deoptimization.hpp Thu May 30 19:51:24 2019 +0200 @@ -72,6 +72,7 @@ // recorded per method Reason_unloaded, // unloaded class or constant pool entry Reason_uninitialized, // bad class state (uninitialized) + Reason_initialized, // class has been fully initialized Reason_unreached, // code is not reached, compiler Reason_unhandled, // arbitrary compiler limitation Reason_constraint, // arbitrary runtime constraint violated
--- a/src/hotspot/share/runtime/globals.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/runtime/globals.hpp Thu May 30 19:51:24 2019 +0200 @@ -444,7 +444,7 @@ diagnostic(bool, LogEvents, true, \ "Enable the various ring buffer event logs") \ \ - diagnostic(uintx, LogEventsBufferEntries, 10, \ + diagnostic(uintx, LogEventsBufferEntries, 20, \ "Number of ring buffer event logs") \ range(1, NOT_LP64(1*K) LP64_ONLY(1*M)) \ \
--- a/src/hotspot/share/runtime/sharedRuntime.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/runtime/sharedRuntime.cpp Thu May 30 19:51:24 2019 +0200 @@ -1314,6 +1314,12 @@ } } } else { + if (VM_Version::supports_fast_class_init_checks() && + invoke_code == Bytecodes::_invokestatic && + callee_method->needs_clinit_barrier() && + callee != NULL && (callee->is_compiled_by_jvmci() || callee->is_aot())) { + return true; // skip patching for JVMCI or AOT code + } CompiledStaticCall* ssc = caller_nm->compiledStaticCall_before(caller_frame.pc()); if (ssc->is_clean()) ssc->set(static_call_info); } @@ -1376,12 +1382,20 @@ } #endif - // Do not patch call site for static call when the class is not - // fully initialized. - if (invoke_code == Bytecodes::_invokestatic && - !callee_method->method_holder()->is_initialized()) { - assert(callee_method->method_holder()->is_linked(), "must be"); - return callee_method; + if (invoke_code == Bytecodes::_invokestatic) { + assert(callee_method->method_holder()->is_initialized() || + callee_method->method_holder()->is_reentrant_initialization(thread), + "invalid class initialization state for invoke_static"); + if (!VM_Version::supports_fast_class_init_checks() && callee_method->needs_clinit_barrier()) { + // In order to keep class initialization check, do not patch call + // site for static call when the class is not fully initialized. + // Proper check is enforced by call site re-resolution on every invocation. + // + // When fast class initialization checks are supported (VM_Version::supports_fast_class_init_checks() == true), + // explicit class initialization check is put in nmethod entry (VEP). + assert(callee_method->method_holder()->is_linked(), "must be"); + return callee_method; + } } // JSR 292 key invariant:
--- a/src/hotspot/share/runtime/vmStructs.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/runtime/vmStructs.cpp Thu May 30 19:51:24 2019 +0200 @@ -2388,6 +2388,7 @@ declare_constant(Deoptimization::Reason_profile_predicate) \ declare_constant(Deoptimization::Reason_unloaded) \ declare_constant(Deoptimization::Reason_uninitialized) \ + declare_constant(Deoptimization::Reason_initialized) \ declare_constant(Deoptimization::Reason_unreached) \ declare_constant(Deoptimization::Reason_unhandled) \ declare_constant(Deoptimization::Reason_constraint) \
--- a/src/hotspot/share/runtime/vm_version.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/runtime/vm_version.hpp Thu May 30 19:51:24 2019 +0200 @@ -171,6 +171,9 @@ // Does this CPU support spin wait instruction? static bool supports_on_spin_wait() { return false; } + // Does platform support fast class initialization checks for static methods? + static bool supports_fast_class_init_checks() { return false; } + static bool print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]); };
--- a/src/hotspot/share/utilities/bitMap.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/bitMap.cpp Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it
--- a/src/hotspot/share/utilities/bitMap.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/bitMap.hpp Thu May 30 19:51:24 2019 +0200 @@ -383,16 +383,16 @@ // Resize the backing bitmap memory. // // Old bits are transfered to the new memory - // and the extended memory is cleared. + // and the extended memory is (optionally) cleared. void resize(idx_t new_size_in_bits, bool clear = true); - // Set up and clear the bitmap memory. + // Set up and (optionally) clear the bitmap memory. // // Precondition: The bitmap was default constructed and has // not yet had memory allocated via resize or initialize. void initialize(idx_t size_in_bits, bool clear = true); - // Set up and clear the bitmap memory. + // Set up and (optionally) clear the bitmap memory. // // Can be called on previously initialized bitmaps. void reinitialize(idx_t size_in_bits, bool clear = true);
--- a/src/hotspot/share/utilities/events.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/events.cpp Thu May 30 19:51:24 2019 +0200 @@ -127,7 +127,7 @@ st.print("Exception <"); h_exception->print_value_on(&st); st.print("%s%s> (" INTPTR_FORMAT ") \n" - "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, + "thrown [%s, line %d]", message ? ": " : "", message ? message : "", - p2i(h_exception()), file, line, p2i(thread)); + p2i(h_exception()), file, line); }
--- a/src/hotspot/share/utilities/events.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/events.hpp Thu May 30 19:51:24 2019 +0200 @@ -232,7 +232,7 @@ }; inline void Events::log(Thread* thread, const char* format, ...) { - if (LogEvents) { + if (LogEvents && _messages != NULL) { va_list ap; va_start(ap, format); _messages->logv(thread, format, ap); @@ -241,7 +241,7 @@ } inline void Events::log_exception(Thread* thread, const char* format, ...) { - if (LogEvents) { + if (LogEvents && _exceptions != NULL) { va_list ap; va_start(ap, format); _exceptions->logv(thread, format, ap); @@ -250,13 +250,13 @@ } inline void Events::log_exception(Thread* thread, Handle h_exception, const char* message, const char* file, int line) { - if (LogEvents) { + if (LogEvents && _exceptions != NULL) { _exceptions->log(thread, h_exception, message, file, line); } } inline void Events::log_redefinition(Thread* thread, const char* format, ...) { - if (LogEvents) { + if (LogEvents && _redefinitions != NULL) { va_list ap; va_start(ap, format); _redefinitions->logv(thread, format, ap); @@ -265,13 +265,13 @@ } inline void Events::log_class_unloading(Thread* thread, InstanceKlass* ik) { - if (LogEvents) { + if (LogEvents && _class_unloading != NULL) { _class_unloading->log(thread, ik); } } inline void Events::log_deopt_message(Thread* thread, const char* format, ...) { - if (LogEvents) { + if (LogEvents && _deopt_messages != NULL) { va_list ap; va_start(ap, format); _deopt_messages->logv(thread, format, ap);
--- a/src/hotspot/share/utilities/globalDefinitions.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/globalDefinitions.hpp Thu May 30 19:51:24 2019 +0200 @@ -97,6 +97,9 @@ #ifndef JLONG_FORMAT #define JLONG_FORMAT INT64_FORMAT #endif +#ifndef JLONG_FORMAT_W +#define JLONG_FORMAT_W(width) INT64_FORMAT_W(width) +#endif #ifndef JULONG_FORMAT #define JULONG_FORMAT UINT64_FORMAT #endif
--- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp Thu May 30 19:51:24 2019 +0200 @@ -250,7 +250,8 @@ #define offsetof(klass,field) offset_of(klass,field) #if defined(_LP64) && defined(__APPLE__) -#define JLONG_FORMAT "%ld" +#define JLONG_FORMAT "%ld" +#define JLONG_FORMAT_W(width) "%" #width "ld" #endif // _LP64 && __APPLE__ #ifndef USE_LIBRARY_BASED_TLS_ONLY
--- a/src/hotspot/share/utilities/ostream.cpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/ostream.cpp Thu May 30 19:51:24 2019 +0200 @@ -939,6 +939,7 @@ buffer_pos = 0; buffer_fixed = false; buffer_max = bufmax; + truncated = false; } bufferedStream::bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax) : outputStream() { @@ -947,12 +948,17 @@ buffer_pos = 0; buffer_fixed = true; buffer_max = bufmax; + truncated = false; } void bufferedStream::write(const char* s, size_t len) { + if (truncated) { + return; + } + if(buffer_pos + len > buffer_max) { - flush(); + flush(); // Note: may be a noop. } size_t end = buffer_pos + len; @@ -960,19 +966,42 @@ if (buffer_fixed) { // if buffer cannot resize, silently truncate len = buffer_length - buffer_pos - 1; + truncated = true; } else { // For small overruns, double the buffer. For larger ones, // increase to the requested size. if (end < buffer_length * 2) { end = buffer_length * 2; } - buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal); - buffer_length = end; + // Impose a cap beyond which the buffer cannot grow - a size which + // in all probability indicates a real error, e.g. faulty printing + // code looping, while not affecting cases of just-very-large-but-its-normal + // output. + const size_t reasonable_cap = MAX2(100 * M, buffer_max * 2); + if (end > reasonable_cap) { + // In debug VM, assert right away. + assert(false, "Exceeded max buffer size for this string."); + // Release VM: silently truncate. We do this since these kind of errors + // are both difficult to predict with testing (depending on logging content) + // and usually not serious enough to kill a production VM for it. + end = reasonable_cap; + size_t remaining = end - buffer_pos; + if (len >= remaining) { + len = remaining - 1; + truncated = true; + } + } + if (buffer_length < end) { + buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal); + buffer_length = end; + } } } - memcpy(buffer + buffer_pos, s, len); - buffer_pos += len; - update_position(s, len); + if (len > 0) { + memcpy(buffer + buffer_pos, s, len); + buffer_pos += len; + update_position(s, len); + } } char* bufferedStream::as_string() {
--- a/src/hotspot/share/utilities/ostream.hpp Thu May 23 22:14:23 2019 +0200 +++ b/src/hotspot/share/utilities/ostream.hpp Thu May 30 19:51:24 2019 +0200 @@ -267,6 +267,7 @@ size_t buffer_max; size_t buffer_length; bool buffer_fixed; + bool truncated; public: bufferedStream(size_t initial_bufsize = 256, size_t bufmax = 1024*1024*10); bufferedStream(char* fixed_buffer, size_t fixed_buffer_size, size_t bufmax = 1024*1024*10);
--- a/src/java.base/macosx/classes/apple/security/KeychainStore.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/macosx/classes/apple/security/KeychainStore.java Thu May 30 19:51:24 2019 +0200 @@ -1050,7 +1050,7 @@ if (random == null) { random = new SecureRandom(); } - salt = random.generateSeed(SALT_LEN); + random.nextBytes(salt); return salt; }
--- a/src/java.base/macosx/classes/java/net/DefaultInterface.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/macosx/classes/java/net/DefaultInterface.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,8 @@ * that returns null. */ +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Enumeration; import java.io.IOException; @@ -82,7 +84,8 @@ continue; boolean ip4 = false, ip6 = false; - Enumeration<InetAddress> addrs = ni.getInetAddresses(); + PrivilegedAction<Enumeration<InetAddress>> pa = ni::getInetAddresses; + Enumeration<InetAddress> addrs = AccessController.doPrivileged(pa); while (addrs.hasMoreElements()) { InetAddress addr = addrs.nextElement(); if (!addr.isAnyLocalAddress()) {
--- a/src/java.base/share/classes/java/io/FilePermission.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/io/FilePermission.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -440,8 +440,8 @@ * <p>A pathname containing an empty string represents an empty path. * * @implNote In this implementation, the - * {@code jdk.io.permissionsUseCanonicalPath} system property dictates how - * the {@code path} argument is processed and stored. + * {@systemProperty jdk.io.permissionsUseCanonicalPath} system property + * dictates how the {@code path} argument is processed and stored. * <P> * If the value of the system property is set to {@code true}, {@code path} * is canonicalized and stored as a String object named {@code cpath}.
--- a/src/java.base/share/classes/java/io/ObjectInputFilter.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/io/ObjectInputFilter.java Thu May 30 19:51:24 2019 +0200 @@ -205,7 +205,7 @@ * <p> * The filter is configured during the initialization of the {@code ObjectInputFilter.Config} * class. For example, by calling {@link #getSerialFilter() Config.getSerialFilter}. - * If the system property {@code jdk.serialFilter} is defined, it is used + * If the system property {@systemProperty jdk.serialFilter} is defined, it is used * to configure the filter. * If the system property is not defined, and the {@link java.security.Security} * property {@code jdk.serialFilter} is defined then it is used to configure the filter.
--- a/src/java.base/share/classes/java/lang/String.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/lang/String.java Thu May 30 19:51:24 2019 +0200 @@ -2691,21 +2691,21 @@ /** * Returns a string whose value is this string, with all leading - * and trailing {@link Character#isWhitespace(int) white space} + * and trailing {@linkplain Character#isWhitespace(int) white space} * removed. * <p> * If this {@code String} object represents an empty string, * or if all code points in this string are - * {@link Character#isWhitespace(int) white space}, then an empty string + * {@linkplain Character#isWhitespace(int) white space}, then an empty string * is returned. * <p> * Otherwise, returns a substring of this string beginning with the first - * code point that is not a {@link Character#isWhitespace(int) white space} + * code point that is not a {@linkplain Character#isWhitespace(int) white space} * up to and including the last code point that is not a - * {@link Character#isWhitespace(int) white space}. + * {@linkplain Character#isWhitespace(int) white space}. * <p> * This method may be used to strip - * {@link Character#isWhitespace(int) white space} from + * {@linkplain Character#isWhitespace(int) white space} from * the beginning and end of a string. * * @return a string whose value is this string, with all leading @@ -2723,19 +2723,19 @@ /** * Returns a string whose value is this string, with all leading - * {@link Character#isWhitespace(int) white space} removed. + * {@linkplain Character#isWhitespace(int) white space} removed. * <p> * If this {@code String} object represents an empty string, * or if all code points in this string are - * {@link Character#isWhitespace(int) white space}, then an empty string + * {@linkplain Character#isWhitespace(int) white space}, then an empty string * is returned. * <p> * Otherwise, returns a substring of this string beginning with the first - * code point that is not a {@link Character#isWhitespace(int) white space} + * code point that is not a {@linkplain Character#isWhitespace(int) white space} * up to and including the last code point of this string. * <p> * This method may be used to trim - * {@link Character#isWhitespace(int) white space} from + * {@linkplain Character#isWhitespace(int) white space} from * the beginning of a string. * * @return a string whose value is this string, with all leading white @@ -2753,19 +2753,19 @@ /** * Returns a string whose value is this string, with all trailing - * {@link Character#isWhitespace(int) white space} removed. + * {@linkplain Character#isWhitespace(int) white space} removed. * <p> * If this {@code String} object represents an empty string, * or if all characters in this string are - * {@link Character#isWhitespace(int) white space}, then an empty string + * {@linkplain Character#isWhitespace(int) white space}, then an empty string * is returned. * <p> * Otherwise, returns a substring of this string beginning with the first * code point of this string up to and including the last code point - * that is not a {@link Character#isWhitespace(int) white space}. + * that is not a {@linkplain Character#isWhitespace(int) white space}. * <p> * This method may be used to trim - * {@link Character#isWhitespace(int) white space} from + * {@linkplain Character#isWhitespace(int) white space} from * the end of a string. * * @return a string whose value is this string, with all trailing white @@ -2783,11 +2783,11 @@ /** * Returns {@code true} if the string is empty or contains only - * {@link Character#isWhitespace(int) white space} codepoints, + * {@linkplain Character#isWhitespace(int) white space} codepoints, * otherwise {@code false}. * * @return {@code true} if the string is empty or contains only - * {@link Character#isWhitespace(int) white space} codepoints, + * {@linkplain Character#isWhitespace(int) white space} codepoints, * otherwise {@code false} * * @see Character#isWhitespace(int) @@ -2845,10 +2845,10 @@ * beginning of each line. * <p> * If {@code n < 0} then up to {@code n} - * {@link Character#isWhitespace(int) white space characters} are removed + * {@linkplain Character#isWhitespace(int) white space characters} are removed * from the beginning of each line. If a given line does not contain * sufficient white space then all leading - * {@link Character#isWhitespace(int) white space characters} are removed. + * {@linkplain Character#isWhitespace(int) white space characters} are removed. * Each white space character is treated as a single character. In * particular, the tab character {@code "\t"} (U+0009) is considered a * single character; it is not expanded. @@ -2857,7 +2857,7 @@ * terminators are still normalized. * * @param n number of leading - * {@link Character#isWhitespace(int) white space characters} + * {@linkplain Character#isWhitespace(int) white space characters} * to add or remove * * @return string with indentation adjusted and line endings normalized
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Thu May 30 19:51:24 2019 +0200 @@ -4980,8 +4980,10 @@ // Step 1C: determine loop return type. // Step 1D: check other types. - final Class<?> loopReturnType = fini.stream().filter(Objects::nonNull).map(MethodHandle::type). - map(MethodType::returnType).findFirst().orElse(void.class); + // local variable required here; see JDK-8223553 + Stream<Class<?>> cstream = fini.stream().filter(Objects::nonNull).map(MethodHandle::type) + .map(MethodType::returnType); + final Class<?> loopReturnType = cstream.findFirst().orElse(void.class); loopChecks1cd(pred, fini, loopReturnType); // Step 2: determine parameter lists.
--- a/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,9 +28,11 @@ import java.io.IOException; import java.util.Collections; import java.util.HashSet; +import java.util.Objects; import java.util.Set; import sun.net.ResourceManager; +import sun.net.ext.ExtendedSocketOptions; import sun.security.action.GetPropertyAction; /** @@ -88,26 +90,6 @@ } /** - * Returns a set of SocketOptions supported by this impl and by this impl's - * socket (Socket or ServerSocket) - * - * @return a Set of SocketOptions - */ - @Override - protected Set<SocketOption<?>> supportedOptions() { - Set<SocketOption<?>> options; - if (isReusePortAvailable()) { - options = new HashSet<>(); - options.addAll(super.supportedOptions()); - options.add(StandardSocketOptions.SO_REUSEPORT); - options = Collections.unmodifiableSet(options); - } else { - options = super.supportedOptions(); - } - return options; - } - - /** * Creates a datagram socket */ protected synchronized void create() throws SocketException { @@ -400,6 +382,125 @@ return result; } + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + + private static final Set<SocketOption<?>> datagramSocketOptions = datagramSocketOptions(); + private static final Set<SocketOption<?>> multicastSocketOptions = multicastSocketOptions(); + + private static Set<SocketOption<?>> datagramSocketOptions() { + HashSet<SocketOption<?>> options = new HashSet<>(); + options.add(StandardSocketOptions.SO_SNDBUF); + options.add(StandardSocketOptions.SO_RCVBUF); + options.add(StandardSocketOptions.SO_REUSEADDR); + options.add(StandardSocketOptions.IP_TOS); + if (isReusePortAvailable()) + options.add(StandardSocketOptions.SO_REUSEPORT); + options.addAll(ExtendedSocketOptions.datagramSocketOptions()); + return Collections.unmodifiableSet(options); + } + + private static Set<SocketOption<?>> multicastSocketOptions() { + HashSet<SocketOption<?>> options = new HashSet<>(); + options.add(StandardSocketOptions.SO_SNDBUF); + options.add(StandardSocketOptions.SO_RCVBUF); + options.add(StandardSocketOptions.SO_REUSEADDR); + options.add(StandardSocketOptions.IP_TOS); + options.add(StandardSocketOptions.IP_MULTICAST_IF); + options.add(StandardSocketOptions.IP_MULTICAST_TTL); + options.add(StandardSocketOptions.IP_MULTICAST_LOOP); + if (isReusePortAvailable()) + options.add(StandardSocketOptions.SO_REUSEPORT); + options.addAll(ExtendedSocketOptions.datagramSocketOptions()); + return Collections.unmodifiableSet(options); + } + + @Override + protected Set<SocketOption<?>> supportedOptions() { + if (getDatagramSocket() instanceof MulticastSocket) + return multicastSocketOptions; + else + return datagramSocketOptions; + } + + @Override + protected <T> void setOption(SocketOption<T> name, T value) throws IOException { + Objects.requireNonNull(name); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + if (!name.type().isInstance(value)) + throw new IllegalArgumentException("Invalid value '" + value + "'"); + + if (isClosed()) + throw new SocketException("Socket closed"); + + if (name == StandardSocketOptions.SO_SNDBUF) { + if (((Integer)value).intValue() < 0) + throw new IllegalArgumentException("Invalid send buffer size:" + value); + setOption(SocketOptions.SO_SNDBUF, value); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + if (((Integer)value).intValue() < 0) + throw new IllegalArgumentException("Invalid recv buffer size:" + value); + setOption(SocketOptions.SO_RCVBUF, value); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_REUSEPORT) { + setOption(SocketOptions.SO_REUSEPORT, value); + } else if (name == StandardSocketOptions.IP_TOS) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid IP_TOS value: " + value); + setOption(SocketOptions.IP_TOS, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF ) { + setOption(SocketOptions.IP_MULTICAST_IF2, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid TTL/hop value: " + value); + setTimeToLive((Integer)value); + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP) { + setOption(SocketOptions.IP_MULTICAST_LOOP, value); + } else if (extendedOptions.isOptionSupported(name)) { + extendedOptions.setOption(fd, name, value); + } else { + throw new AssertionError("unknown option :" + name); + } + } + + @Override + @SuppressWarnings("unchecked") + protected <T> T getOption(SocketOption<T> name) throws IOException { + Objects.requireNonNull(name); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + if (isClosed()) + throw new SocketException("Socket closed"); + + if (name == StandardSocketOptions.SO_SNDBUF) { + return (T) getOption(SocketOptions.SO_SNDBUF); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + return (T) getOption(SocketOptions.SO_RCVBUF); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + return (T) getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_REUSEPORT) { + return (T) getOption(SocketOptions.SO_REUSEPORT); + } else if (name == StandardSocketOptions.IP_TOS) { + return (T) getOption(SocketOptions.IP_TOS); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF) { + return (T) getOption(SocketOptions.IP_MULTICAST_IF2); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL) { + return (T) ((Integer) getTimeToLive()); + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP) { + return (T) getOption(SocketOptions.IP_MULTICAST_LOOP); + } else if (extendedOptions.isOptionSupported(name)) { + return (T) extendedOptions.getOption(fd, name); + } else { + throw new AssertionError("unknown option: " + name); + } + } + protected abstract void datagramSocketCreate() throws SocketException; protected abstract void datagramSocketClose(); protected abstract void socketSetOption(int opt, Object val)
--- a/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java Thu May 30 19:51:24 2019 +0200 @@ -35,12 +35,14 @@ import java.security.PrivilegedExceptionAction; import java.util.Collections; import java.util.HashSet; +import java.util.Objects; import java.util.Set; import sun.net.ConnectionResetException; import sun.net.NetHooks; import sun.net.PlatformSocketImpl; import sun.net.ResourceManager; +import sun.net.ext.ExtendedSocketOptions; import sun.net.util.SocketExceptions; /** @@ -84,6 +86,9 @@ */ protected boolean stream; + /* whether this is a server or not */ + final boolean isServer; + /** * Load net library into runtime. */ @@ -112,27 +117,7 @@ } AbstractPlainSocketImpl(boolean isServer) { - super(isServer); - } - - /** - * Returns a set of SocketOptions supported by this impl and by this impl's - * socket (Socket or ServerSocket) - * - * @return a Set of SocketOptions - */ - @Override - protected Set<SocketOption<?>> supportedOptions() { - Set<SocketOption<?>> options; - if (isReusePortAvailable()) { - options = new HashSet<>(); - options.addAll(super.supportedOptions()); - options.add(StandardSocketOptions.SO_REUSEPORT); - options = Collections.unmodifiableSet(options); - } else { - options = super.supportedOptions(); - } - return options; + this.isServer = isServer; } /** @@ -394,6 +379,121 @@ } } + static final ExtendedSocketOptions extendedOptions = + ExtendedSocketOptions.getInstance(); + + private static final Set<SocketOption<?>> clientSocketOptions = clientSocketOptions(); + private static final Set<SocketOption<?>> serverSocketOptions = serverSocketOptions(); + + private static Set<SocketOption<?>> clientSocketOptions() { + HashSet<SocketOption<?>> options = new HashSet<>(); + options.add(StandardSocketOptions.SO_KEEPALIVE); + options.add(StandardSocketOptions.SO_SNDBUF); + options.add(StandardSocketOptions.SO_RCVBUF); + options.add(StandardSocketOptions.SO_REUSEADDR); + options.add(StandardSocketOptions.SO_LINGER); + options.add(StandardSocketOptions.IP_TOS); + options.add(StandardSocketOptions.TCP_NODELAY); + if (isReusePortAvailable()) + options.add(StandardSocketOptions.SO_REUSEPORT); + options.addAll(ExtendedSocketOptions.clientSocketOptions()); + return Collections.unmodifiableSet(options); + } + + private static Set<SocketOption<?>> serverSocketOptions() { + HashSet<SocketOption<?>> options = new HashSet<>(); + options.add(StandardSocketOptions.SO_RCVBUF); + options.add(StandardSocketOptions.SO_REUSEADDR); + options.add(StandardSocketOptions.IP_TOS); + if (isReusePortAvailable()) + options.add(StandardSocketOptions.SO_REUSEPORT); + options.addAll(ExtendedSocketOptions.serverSocketOptions()); + return Collections.unmodifiableSet(options); + } + + @Override + protected Set<SocketOption<?>> supportedOptions() { + if (isServer) + return serverSocketOptions; + else + return clientSocketOptions; + } + + @Override + protected <T> void setOption(SocketOption<T> name, T value) throws IOException { + Objects.requireNonNull(name); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + if (!name.type().isInstance(value)) + throw new IllegalArgumentException("Invalid value '" + value + "'"); + + if (isClosedOrPending()) + throw new SocketException("Socket closed"); + + if (name == StandardSocketOptions.SO_KEEPALIVE) { + setOption(SocketOptions.SO_KEEPALIVE, value); + } else if (name == StandardSocketOptions.SO_SNDBUF) { + if (((Integer)value).intValue() < 0) + throw new IllegalArgumentException("Invalid send buffer size:" + value); + setOption(SocketOptions.SO_SNDBUF, value); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + if (((Integer)value).intValue() < 0) + throw new IllegalArgumentException("Invalid recv buffer size:" + value); + setOption(SocketOptions.SO_RCVBUF, value); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_REUSEPORT) { + setOption(SocketOptions.SO_REUSEPORT, value); + } else if (name == StandardSocketOptions.SO_LINGER ) { + setOption(SocketOptions.SO_LINGER, value); + } else if (name == StandardSocketOptions.IP_TOS) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid IP_TOS value: " + value); + setOption(SocketOptions.IP_TOS, value); + } else if (name == StandardSocketOptions.TCP_NODELAY) { + setOption(SocketOptions.TCP_NODELAY, value); + } else if (extendedOptions.isOptionSupported(name)) { + extendedOptions.setOption(fd, name, value); + } else { + throw new AssertionError("unknown option: " + name); + } + } + + @Override + @SuppressWarnings("unchecked") + protected <T> T getOption(SocketOption<T> name) throws IOException { + Objects.requireNonNull(name); + if (!supportedOptions().contains(name)) + throw new UnsupportedOperationException("'" + name + "' not supported"); + + if (isClosedOrPending()) + throw new SocketException("Socket closed"); + + if (name == StandardSocketOptions.SO_KEEPALIVE) { + return (T)getOption(SocketOptions.SO_KEEPALIVE); + } else if (name == StandardSocketOptions.SO_SNDBUF) { + return (T)getOption(SocketOptions.SO_SNDBUF); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + return (T)getOption(SocketOptions.SO_RCVBUF); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + return (T)getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_REUSEPORT) { + return (T)getOption(SocketOptions.SO_REUSEPORT); + } else if (name == StandardSocketOptions.SO_LINGER) { + return (T)getOption(SocketOptions.SO_LINGER); + } else if (name == StandardSocketOptions.IP_TOS) { + return (T)getOption(SocketOptions.IP_TOS); + } else if (name == StandardSocketOptions.TCP_NODELAY) { + return (T)getOption(SocketOptions.TCP_NODELAY); + } else if (extendedOptions.isOptionSupported(name)) { + return (T) extendedOptions.getOption(fd, name); + } else { + throw new AssertionError("unknown option: " + name); + } + } + /** * The workhorse of the connection operation. Tries several times to * establish a connection to the given <host, port>. If unsuccessful,
--- a/src/java.base/share/classes/java/net/DatagramSocket.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/net/DatagramSocket.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.nio.channels.DatagramChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; +import java.util.Objects; import java.util.Set; import java.util.Collections; @@ -1343,6 +1344,9 @@ public <T> DatagramSocket setOption(SocketOption<T> name, T value) throws IOException { + Objects.requireNonNull(name); + if (isClosed()) + throw new SocketException("Socket is closed"); getImpl().setOption(name, value); return this; } @@ -1371,6 +1375,9 @@ * @since 9 */ public <T> T getOption(SocketOption<T> name) throws IOException { + Objects.requireNonNull(name); + if (isClosed()) + throw new SocketException("Socket is closed"); return getImpl().getOption(name); }
--- a/src/java.base/share/classes/java/net/DatagramSocketImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/net/DatagramSocketImpl.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.FileDescriptor; import java.io.IOException; +import java.util.Objects; import java.util.Set; /** @@ -265,123 +266,69 @@ /** * Called to set a socket option. * + * @implSpec + * The default implementation of this method first checks that the given + * socket option {code name} is not null, then throws {@code + * UnsupportedOperationException}. Subclasses should override this method + * with an appropriate implementation. + * * @param <T> The type of the socket option value * @param name The socket option - * * @param value The value of the socket option. A value of {@code null} * may be valid for some options. * * @throws UnsupportedOperationException if the DatagramSocketImpl does not * support the option - * + * @throws IllegalArgumentException if the value is not valid for + * the option + * @throws IOException if an I/O error occurs, or if the socket is closed * @throws NullPointerException if name is {@code null} - * @throws IOException if an I/O problem occurs while attempting to set the option + * * @since 9 */ protected <T> void setOption(SocketOption<T> name, T value) throws IOException { - if (name == StandardSocketOptions.SO_SNDBUF) { - setOption(SocketOptions.SO_SNDBUF, value); - } else if (name == StandardSocketOptions.SO_RCVBUF) { - setOption(SocketOptions.SO_RCVBUF, value); - } else if (name == StandardSocketOptions.SO_REUSEADDR) { - setOption(SocketOptions.SO_REUSEADDR, value); - } else if (name == StandardSocketOptions.SO_REUSEPORT && - supportedOptions().contains(name)) { - setOption(SocketOptions.SO_REUSEPORT, value); - } else if (name == StandardSocketOptions.IP_TOS) { - setOption(SocketOptions.IP_TOS, value); - } else if (name == StandardSocketOptions.IP_MULTICAST_IF && - (getDatagramSocket() instanceof MulticastSocket)) { - setOption(SocketOptions.IP_MULTICAST_IF2, value); - } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && - (getDatagramSocket() instanceof MulticastSocket)) { - if (! (value instanceof Integer)) { - throw new IllegalArgumentException("not an integer"); - } - setTimeToLive((Integer)value); - } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && - (getDatagramSocket() instanceof MulticastSocket)) { - setOption(SocketOptions.IP_MULTICAST_LOOP, value); - } else { - throw new UnsupportedOperationException("unsupported option"); - } + Objects.requireNonNull(name); + throw new UnsupportedOperationException("'" + name + "' not supported"); } /** * Called to get a socket option. * - * @return the socket option + * @implSpec + * The default implementation of this method first checks that the given + * socket option {code name} is not null, then throws {@code + * UnsupportedOperationException}. Subclasses should override this method + * with an appropriate implementation. + * * @param <T> The type of the socket option value * @param name The socket option + * @return the socket option * * @throws UnsupportedOperationException if the DatagramSocketImpl does not * support the option - * + * @throws IOException if an I/O error occurs, or if the socket is closed * @throws NullPointerException if name is {@code null} - * @throws IOException if an I/O problem occurs while attempting to set the option * * @since 9 */ - @SuppressWarnings("unchecked") protected <T> T getOption(SocketOption<T> name) throws IOException { - if (name == StandardSocketOptions.SO_SNDBUF) { - return (T) getOption(SocketOptions.SO_SNDBUF); - } else if (name == StandardSocketOptions.SO_RCVBUF) { - return (T) getOption(SocketOptions.SO_RCVBUF); - } else if (name == StandardSocketOptions.SO_REUSEADDR) { - return (T) getOption(SocketOptions.SO_REUSEADDR); - } else if (name == StandardSocketOptions.SO_REUSEPORT && - supportedOptions().contains(name)) { - return (T) getOption(SocketOptions.SO_REUSEPORT); - } else if (name == StandardSocketOptions.IP_TOS) { - return (T) getOption(SocketOptions.IP_TOS); - } else if (name == StandardSocketOptions.IP_MULTICAST_IF && - (getDatagramSocket() instanceof MulticastSocket)) { - return (T) getOption(SocketOptions.IP_MULTICAST_IF2); - } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && - (getDatagramSocket() instanceof MulticastSocket)) { - Integer ttl = getTimeToLive(); - return (T)ttl; - } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && - (getDatagramSocket() instanceof MulticastSocket)) { - return (T) getOption(SocketOptions.IP_MULTICAST_LOOP); - } else { - throw new UnsupportedOperationException("unsupported option"); - } - } - - private static final Set<SocketOption<?>> dgSocketOptions; - - private static final Set<SocketOption<?>> mcSocketOptions; - - static { - dgSocketOptions = Set.of(StandardSocketOptions.SO_SNDBUF, - StandardSocketOptions.SO_RCVBUF, - StandardSocketOptions.SO_REUSEADDR, - StandardSocketOptions.IP_TOS); - - mcSocketOptions = Set.of(StandardSocketOptions.SO_SNDBUF, - StandardSocketOptions.SO_RCVBUF, - StandardSocketOptions.SO_REUSEADDR, - StandardSocketOptions.IP_TOS, - StandardSocketOptions.IP_MULTICAST_IF, - StandardSocketOptions.IP_MULTICAST_TTL, - StandardSocketOptions.IP_MULTICAST_LOOP); + Objects.requireNonNull(name); + throw new UnsupportedOperationException("'" + name + "' not supported"); } /** * Returns a set of SocketOptions supported by this impl * and by this impl's socket (DatagramSocket or MulticastSocket) * + * @implSpec + * The default implementation of this method returns an empty set. + * Subclasses should override this method with an appropriate implementation. + * * @return a Set of SocketOptions * * @since 9 */ protected Set<SocketOption<?>> supportedOptions() { - if (getDatagramSocket() instanceof MulticastSocket) { - return mcSocketOptions; - } else { - return dgSocketOptions; - } + return Set.of(); } }
--- a/src/java.base/share/classes/java/net/ServerSocket.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/net/ServerSocket.java Thu May 30 19:51:24 2019 +0200 @@ -817,7 +817,8 @@ * Returns the implementation address and implementation port of * this socket as a {@code String}. * <p> - * If there is a security manager set, its {@code checkConnect} method is + * If there is a security manager set, and this socket is + * {@linkplain #isBound bound}, its {@code checkConnect} method is * called with the local address and {@code -1} as its arguments to see * if the operation is allowed. If the operation is not allowed, * an {@code InetAddress} representing the @@ -831,7 +832,7 @@ return "ServerSocket[unbound]"; InetAddress in; if (System.getSecurityManager() != null) - in = InetAddress.getLoopbackAddress(); + in = getInetAddress(); else in = impl.getInetAddress(); return "ServerSocket[addr=" + in + @@ -1025,6 +1026,9 @@ public <T> ServerSocket setOption(SocketOption<T> name, T value) throws IOException { + Objects.requireNonNull(name); + if (isClosed()) + throw new SocketException("Socket is closed"); getImpl().setOption(name, value); return this; } @@ -1053,6 +1057,9 @@ * @since 9 */ public <T> T getOption(SocketOption<T> name) throws IOException { + Objects.requireNonNull(name); + if (isClosed()) + throw new SocketException("Socket is closed"); return getImpl().getOption(name); }
--- a/src/java.base/share/classes/java/net/Socket.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/net/Socket.java Thu May 30 19:51:24 2019 +0200 @@ -33,6 +33,7 @@ import java.nio.channels.SocketChannel; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Objects; import java.util.Set; import java.util.Collections; @@ -1786,6 +1787,9 @@ * @since 9 */ public <T> Socket setOption(SocketOption<T> name, T value) throws IOException { + Objects.requireNonNull(name); + if (isClosed()) + throw new SocketException("Socket is closed"); getImpl().setOption(name, value); return this; } @@ -1815,6 +1819,9 @@ */ @SuppressWarnings("unchecked") public <T> T getOption(SocketOption<T> name) throws IOException { + Objects.requireNonNull(name); + if (isClosed()) + throw new SocketException("Socket is closed"); return getImpl().getOption(name); }
--- a/src/java.base/share/classes/java/net/SocketImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/net/SocketImpl.java Thu May 30 19:51:24 2019 +0200 @@ -25,33 +25,63 @@ package java.net; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.FileDescriptor; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Objects; import java.util.Set; +import sun.net.NetProperties; import sun.net.PlatformSocketImpl; +import sun.nio.ch.NioSocketImpl; /** * The abstract class {@code SocketImpl} is a common superclass * of all classes that actually implement sockets. It is used to * create both client and server sockets. - * <p> - * A "plain" socket implements these methods exactly as - * described, without attempting to go through a firewall or proxy. + * + * @implNote Client and server sockets created with the {@code Socket} and + * {@code SocketServer} public constructors create a system-default + * {@code SocketImpl}. The JDK historically used a {@code SocketImpl} + * implementation type named "PlainSocketImpl" that has since been replaced by a + * newer implementation. The JDK continues to ship with the older implementation + * to allow code to run that depends on unspecified behavior that differs between + * the old and new implementations. The old implementation will be used if the + * Java virtual machine is started with the system property {@systemProperty + * jdk.net.usePlainSocketImpl} set to use the old implementation. It may also be + * set in the JDK's network configuration file, located in {@code + * ${java.home}/conf/net.properties}. The value of the property is the string + * representation of a boolean. If set without a value then it defaults to {@code + * true}, hence running with {@code -Djdk.net.usePlainSocketImpl} or {@code + * -Djdk.net.usePlainSocketImpl=true} will configure the Java virtual machine + * to use the old implementation. The property and old implementation will be + * removed in a future version. * * @author unascribed * @since 1.0 */ public abstract class SocketImpl implements SocketOptions { + private static final boolean USE_PLAINSOCKETIMPL = usePlainSocketImpl(); + + private static boolean usePlainSocketImpl() { + PrivilegedAction<String> pa = () -> NetProperties.get("jdk.net.usePlainSocketImpl"); + String s = AccessController.doPrivileged(pa); + return (s != null) && !s.equalsIgnoreCase("false"); + } /** * Creates an instance of platform's SocketImpl */ @SuppressWarnings("unchecked") static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) { - return (S) new PlainSocketImpl(server); + if (USE_PLAINSOCKETIMPL) { + return (S) new PlainSocketImpl(server); + } else { + return (S) new NioSocketImpl(server); + } } /** @@ -75,21 +105,9 @@ protected int localport; /** - * Whether this is a server or not. - */ - final boolean isServer; - - - SocketImpl(boolean isServer) { - this.isServer = isServer; - } - - /** * Initialize a new instance of this class */ - public SocketImpl() { - this.isServer = false; - } + public SocketImpl() { } /** * Creates either a stream or a datagram socket. @@ -376,79 +394,54 @@ /** * Called to set a socket option. * + * @implSpec + * The default implementation of this method first checks that the given + * socket option {code name} is not null, then throws {@code + * UnsupportedOperationException}. Subclasses should override this method + * with an appropriate implementation. + * * @param <T> The type of the socket option value * @param name The socket option - * * @param value The value of the socket option. A value of {@code null} * may be valid for some options. * * @throws UnsupportedOperationException if the SocketImpl does not * support the option - * - * @throws IOException if an I/O error occurs, or if the socket is closed. + * @throws IllegalArgumentException if the value is not valid for + * the option + * @throws IOException if an I/O error occurs, or if the socket is closed + * @throws NullPointerException if name is {@code null} * * @since 9 */ protected <T> void setOption(SocketOption<T> name, T value) throws IOException { - if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) { - setOption(SocketOptions.SO_KEEPALIVE, value); - } else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) { - setOption(SocketOptions.SO_SNDBUF, value); - } else if (name == StandardSocketOptions.SO_RCVBUF) { - setOption(SocketOptions.SO_RCVBUF, value); - } else if (name == StandardSocketOptions.SO_REUSEADDR) { - setOption(SocketOptions.SO_REUSEADDR, value); - } else if (name == StandardSocketOptions.SO_REUSEPORT && - supportedOptions().contains(name)) { - setOption(SocketOptions.SO_REUSEPORT, value); - } else if (name == StandardSocketOptions.SO_LINGER && !isServer) { - setOption(SocketOptions.SO_LINGER, value); - } else if (name == StandardSocketOptions.IP_TOS) { - setOption(SocketOptions.IP_TOS, value); - } else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) { - setOption(SocketOptions.TCP_NODELAY, value); - } else { - throw new UnsupportedOperationException("unsupported option"); - } + Objects.requireNonNull(name); + throw new UnsupportedOperationException("'" + name + "' not supported"); } /** * Called to get a socket option. * + * @implSpec + * The default implementation of this method first checks that the given + * socket option {code name} is not null, then throws {@code + * UnsupportedOperationException}. Subclasses should override this method + * with an appropriate implementation. + * * @param <T> The type of the socket option value * @param name The socket option - * * @return the value of the named option * * @throws UnsupportedOperationException if the SocketImpl does not - * support the option. - * - * @throws IOException if an I/O error occurs, or if the socket is closed. + * support the option + * @throws IOException if an I/O error occurs, or if the socket is closed + * @throws NullPointerException if name is {@code null} * * @since 9 */ - @SuppressWarnings("unchecked") protected <T> T getOption(SocketOption<T> name) throws IOException { - if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) { - return (T)getOption(SocketOptions.SO_KEEPALIVE); - } else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) { - return (T)getOption(SocketOptions.SO_SNDBUF); - } else if (name == StandardSocketOptions.SO_RCVBUF) { - return (T)getOption(SocketOptions.SO_RCVBUF); - } else if (name == StandardSocketOptions.SO_REUSEADDR) { - return (T)getOption(SocketOptions.SO_REUSEADDR); - } else if (name == StandardSocketOptions.SO_REUSEPORT && - supportedOptions().contains(name)) { - return (T)getOption(SocketOptions.SO_REUSEPORT); - } else if (name == StandardSocketOptions.SO_LINGER && !isServer) { - return (T)getOption(SocketOptions.SO_LINGER); - } else if (name == StandardSocketOptions.IP_TOS) { - return (T)getOption(SocketOptions.IP_TOS); - } else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) { - return (T)getOption(SocketOptions.TCP_NODELAY); - } else { - throw new UnsupportedOperationException("unsupported option"); - } + Objects.requireNonNull(name); + throw new UnsupportedOperationException("'" + name + "' not supported"); } /** @@ -464,37 +457,19 @@ } catch (IOException ignore) { } } - private static final Set<SocketOption<?>> socketOptions; - - private static final Set<SocketOption<?>> serverSocketOptions; - - static { - socketOptions = Set.of(StandardSocketOptions.SO_KEEPALIVE, - StandardSocketOptions.SO_SNDBUF, - StandardSocketOptions.SO_RCVBUF, - StandardSocketOptions.SO_REUSEADDR, - StandardSocketOptions.SO_LINGER, - StandardSocketOptions.IP_TOS, - StandardSocketOptions.TCP_NODELAY); - - serverSocketOptions = Set.of(StandardSocketOptions.SO_RCVBUF, - StandardSocketOptions.SO_REUSEADDR, - StandardSocketOptions.IP_TOS); - } - /** * Returns a set of SocketOptions supported by this impl * and by this impl's socket (Socket or ServerSocket) * + * @implSpec + * The default implementation of this method returns an empty set. + * Subclasses should override this method with an appropriate implementation. + * * @return a Set of SocketOptions * * @since 9 */ protected Set<SocketOption<?>> supportedOptions() { - if (!isServer) { - return socketOptions; - } else { - return serverSocketOptions; - } + return Set.of(); } }
--- a/src/java.base/share/classes/java/nio/channels/AsynchronousChannelGroup.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/nio/channels/AsynchronousChannelGroup.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,7 +70,9 @@ * </thead> * <tbody> * <tr> - * <th scope="row"> {@code java.nio.channels.DefaultThreadPool.threadFactory} </th> + * <th scope="row"> + * {@systemProperty java.nio.channels.DefaultThreadPool.threadFactory} + * </th> * <td> The value of this property is taken to be the fully-qualified name * of a concrete {@link java.util.concurrent.ThreadFactory ThreadFactory} * class. The class is loaded using the system class loader and instantiated. @@ -81,7 +83,9 @@ * construction of the default group. </td> * </tr> * <tr> - * <th scope="row"> {@code java.nio.channels.DefaultThreadPool.initialSize} </th> + * <th scope="row"> + * {@systemProperty java.nio.channels.DefaultThreadPool.initialSize} + * </th> * <td> The value of the {@code initialSize} parameter for the default * group (see {@link #withCachedThreadPool withCachedThreadPool}). * The value of the property is taken to be the {@code String}
--- a/src/java.base/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,10 +138,10 @@ * <ol> * * <li><p> If the system property - * {@code java.nio.channels.spi.AsynchronousChannelProvider} is defined - * then it is taken to be the fully-qualified name of a concrete provider class. - * The class is loaded and instantiated; if this process fails then an - * unspecified error is thrown. </p></li> + * {@systemProperty java.nio.channels.spi.AsynchronousChannelProvider} is + * defined then it is taken to be the fully-qualified name of a concrete + * provider class. The class is loaded and instantiated; if this process + * fails then an unspecified error is thrown. </p></li> * * <li><p> If a provider class has been installed in a jar file that is * visible to the system class loader, and that jar file contains a
--- a/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,10 +143,10 @@ * <ol> * * <li><p> If the system property - * {@code java.nio.channels.spi.SelectorProvider} is defined then it is - * taken to be the fully-qualified name of a concrete provider class. - * The class is loaded and instantiated; if this process fails then an - * unspecified error is thrown. </p></li> + * {@systemProperty java.nio.channels.spi.SelectorProvider} is defined + * then it is taken to be the fully-qualified name of a concrete provider + * class. The class is loaded and instantiated; if this process fails then + * an unspecified error is thrown. </p></li> * * <li><p> If a provider class has been installed in a jar file that is * visible to the system class loader, and that jar file contains a
--- a/src/java.base/share/classes/java/nio/charset/Charset.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/nio/charset/Charset.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,8 +67,7 @@ * concurrent threads. * * - * <a id="names"></a><a id="charenc"></a> - * <h2>Charset names</h2> + * <h2><a id="names">Charset names</a></h2> * * <p> Charsets are named by strings composed of the following characters: * @@ -138,12 +137,11 @@ * previous canonical name be made into an alias. * * - * <h2>Standard charsets</h2> + * <h2><a id="standard">Standard charsets</a></h2> * * - * - * <p><a id="standard">Every implementation of the Java platform is required to support the - * following standard charsets.</a> Consult the release documentation for your + * <p> Every implementation of the Java platform is required to support the + * following standard charsets. Consult the release documentation for your * implementation to see if any other charsets are supported. The behavior * of such optional charsets may differ between implementations. * @@ -217,7 +215,7 @@ * determined during virtual-machine startup and typically depends upon the * locale and charset being used by the underlying operating system. </p> * - * <p>The {@link StandardCharsets} class defines constants for each of the + * <p> The {@link StandardCharsets} class defines constants for each of the * standard charsets. * * <h2>Terminology</h2>
--- a/src/java.base/share/classes/java/nio/charset/StandardCharsets.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/nio/charset/StandardCharsets.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package java.nio.charset; /** - * Constant definitions for the standard {@link Charset Charsets}. These + * Constant definitions for the standard {@link Charset charsets}. These * charsets are guaranteed to be available on every implementation of the Java * platform. * @@ -44,29 +44,34 @@ } /** - * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the - * Unicode character set + * Seven-bit ASCII, also known as ISO646-US, also known as the + * Basic Latin block of the Unicode character set. */ public static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE; + /** - * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1 + * ISO Latin Alphabet {@literal No. 1}, also known as ISO-LATIN-1. */ public static final Charset ISO_8859_1 = sun.nio.cs.ISO_8859_1.INSTANCE; + /** - * Eight-bit UCS Transformation Format + * Eight-bit UCS Transformation Format. */ public static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE; + /** - * Sixteen-bit UCS Transformation Format, big-endian byte order + * Sixteen-bit UCS Transformation Format, big-endian byte order. */ public static final Charset UTF_16BE = new sun.nio.cs.UTF_16BE(); + /** - * Sixteen-bit UCS Transformation Format, little-endian byte order + * Sixteen-bit UCS Transformation Format, little-endian byte order. */ public static final Charset UTF_16LE = new sun.nio.cs.UTF_16LE(); + /** * Sixteen-bit UCS Transformation Format, byte order identified by an - * optional byte-order mark + * optional byte-order mark. */ public static final Charset UTF_16 = new sun.nio.cs.UTF_16(); }
--- a/src/java.base/share/classes/java/nio/file/spi/FileSystemProvider.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/nio/file/spi/FileSystemProvider.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,7 @@ * provides access to the file systems accessible to the Java virtual machine. * The {@link FileSystems} class defines how file system providers are located * and loaded. The default provider is typically a system-default provider but - * may be overridden if the system property {@code + * may be overridden if the system property {@systemProperty * java.nio.file.spi.DefaultFileSystemProvider} is set. In that case, the * provider has a one argument constructor whose formal parameter type is {@code * FileSystemProvider}. All other providers have a zero argument constructor
--- a/src/java.base/share/classes/java/util/ArrayList.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/util/ArrayList.java Thu May 30 19:51:24 2019 +0200 @@ -1696,6 +1696,7 @@ @Override public void replaceAll(UnaryOperator<E> operator) { replaceAllRange(operator, 0, size); + // TODO(8203662): remove increment of modCount from ... modCount++; }
--- a/src/java.base/share/classes/java/util/Vector.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/util/Vector.java Thu May 30 19:51:24 2019 +0200 @@ -1369,6 +1369,7 @@ es[i] = operator.apply(elementAt(es, i)); if (modCount != expectedModCount) throw new ConcurrentModificationException(); + // TODO(8203662): remove increment of modCount from ... modCount++; }
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Thu May 30 19:51:24 2019 +0200 @@ -1712,9 +1712,8 @@ Map<?,?> m = (Map<?,?>) o; try { Comparator<? super K> cmp = comparator; - @SuppressWarnings("unchecked") - Iterator<Map.Entry<?,?>> it = - (Iterator<Map.Entry<?,?>>)m.entrySet().iterator(); + // See JDK-8223553 for Iterator type wildcard rationale + Iterator<? extends Map.Entry<?,?>> it = m.entrySet().iterator(); if (m instanceof SortedMap && ((SortedMap<?,?>)m).comparator() == cmp) { Node<K,V> b, n;
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java Thu May 30 19:51:24 2019 +0200 @@ -867,8 +867,8 @@ growArray(true); else { phase = 0; // full volatile unlock - if (a[m & (s - 1)] == null) - signal = true; // was empty + if (((s - base) & ~1) == 0) // size 0 or 1 + signal = true; } } return signal; @@ -2667,13 +2667,13 @@ } /** - * Returns an estimate of the total number of tasks stolen from - * one thread's work queue by another. The reported value - * underestimates the actual total number of steals when the pool - * is not quiescent. This value may be useful for monitoring and - * tuning fork/join programs: in general, steal counts should be - * high enough to keep threads busy, but low enough to avoid - * overhead and contention across threads. + * Returns an estimate of the total number of completed tasks that + * were executed by a thread other than their submitter. The + * reported value underestimates the actual total number of steals + * when the pool is not quiescent. This value may be useful for + * monitoring and tuning fork/join programs: in general, steal + * counts should be high enough to keep threads busy, but low + * enough to avoid overhead and contention across threads. * * @return the number of steals */
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java Thu May 30 19:51:24 2019 +0200 @@ -360,7 +360,7 @@ * Returns the current value of this {@code AtomicInteger} as a * {@code long} after a widening primitive conversion, * with memory effects as specified by {@link VarHandle#getVolatile}. - * @jls 5.1.2 Widening Primitive Conversions + * @jls 5.1.2 Widening Primitive Conversion */ public long longValue() { return (long)get(); @@ -370,7 +370,7 @@ * Returns the current value of this {@code AtomicInteger} as a * {@code float} after a widening primitive conversion, * with memory effects as specified by {@link VarHandle#getVolatile}. - * @jls 5.1.2 Widening Primitive Conversions + * @jls 5.1.2 Widening Primitive Conversion */ public float floatValue() { return (float)get(); @@ -380,7 +380,7 @@ * Returns the current value of this {@code AtomicInteger} as a * {@code double} after a widening primitive conversion, * with memory effects as specified by {@link VarHandle#getVolatile}. - * @jls 5.1.2 Widening Primitive Conversions + * @jls 5.1.2 Widening Primitive Conversion */ public double doubleValue() { return (double)get();
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java Thu May 30 19:51:24 2019 +0200 @@ -364,7 +364,7 @@ * Returns the current value of this {@code AtomicLong} as an {@code int} * after a narrowing primitive conversion, * with memory effects as specified by {@link VarHandle#getVolatile}. - * @jls 5.1.3 Narrowing Primitive Conversions + * @jls 5.1.3 Narrowing Primitive Conversion */ public int intValue() { return (int)get(); @@ -383,7 +383,7 @@ * Returns the current value of this {@code AtomicLong} as a {@code float} * after a widening primitive conversion, * with memory effects as specified by {@link VarHandle#getVolatile}. - * @jls 5.1.2 Widening Primitive Conversions + * @jls 5.1.2 Widening Primitive Conversion */ public float floatValue() { return (float)get(); @@ -393,7 +393,7 @@ * Returns the current value of this {@code AtomicLong} as a {@code double} * after a widening primitive conversion, * with memory effects as specified by {@link VarHandle#getVolatile}. - * @jls 5.1.2 Widening Primitive Conversions + * @jls 5.1.2 Widening Primitive Conversion */ public double doubleValue() { return (double)get();
--- a/src/java.base/share/classes/java/util/regex/Pattern.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/java/util/regex/Pattern.java Thu May 30 19:51:24 2019 +0200 @@ -3271,28 +3271,33 @@ case '+': return curly(prev, 1); case '{': - ch = temp[cursor+1]; + ch = skip(); if (ASCII.isDigit(ch)) { - skip(); - int cmin = 0; - do { - cmin = cmin * 10 + (ch - '0'); - } while (ASCII.isDigit(ch = read())); - int cmax = cmin; - if (ch == ',') { - ch = read(); - cmax = MAX_REPS; - if (ch != '}') { - cmax = 0; - while (ASCII.isDigit(ch)) { - cmax = cmax * 10 + (ch - '0'); - ch = read(); + int cmin = 0, cmax; + try { + do { + cmin = Math.addExact(Math.multiplyExact(cmin, 10), + ch - '0'); + } while (ASCII.isDigit(ch = read())); + cmax = cmin; + if (ch == ',') { + ch = read(); + cmax = MAX_REPS; + if (ch != '}') { + cmax = 0; + while (ASCII.isDigit(ch)) { + cmax = Math.addExact(Math.multiplyExact(cmax, 10), + ch - '0'); + ch = read(); + } } } + } catch (ArithmeticException ae) { + throw error("Illegal repetition range"); } if (ch != '}') throw error("Unclosed counted closure"); - if (((cmin) | (cmax) | (cmax - cmin)) < 0) + if (cmax < cmin) throw error("Illegal repetition range"); Curly curly; ch = peek();
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java Thu May 30 19:51:24 2019 +0200 @@ -190,10 +190,11 @@ throw new IllegalArgumentException("Fragment component present"); } String path = uri.getPath(); - if (path == null || path.charAt(0) != '/') { + if (path == null || path.charAt(0) != '/' || path.contains("..")) { throw new IllegalArgumentException("Invalid path component"); } - return getTheFileSystem().getPath(path); + + return getTheFileSystem().getPath("/modules" + path); } private FileSystem getTheFileSystem() {
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java Thu May 30 19:51:24 2019 +0200 @@ -25,6 +25,7 @@ package jdk.internal.jrtfs; import java.io.File; +import java.io.IOError; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -170,7 +171,16 @@ @Override public final URI toUri() { try { - return new URI("jrt", toAbsolutePath().path, null); + String p = toAbsolutePath().path; + if (!p.startsWith("/modules") || p.contains("..")) { + throw new IOError(new RuntimeException(p + " cannot be represented as URI")); + } + + p = p.substring("/modules".length()); + if (p.isEmpty()) { + p = "/"; + } + return new URI("jrt", p, null); } catch (URISyntaxException ex) { throw new AssertionError(ex); }
--- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -166,6 +166,8 @@ \ configuration and continue\n\ \ -Xss<size> set java thread stack size\n\ \ -Xverify sets the mode of the bytecode verifier\n\ +\ Note that option -Xverify:none is deprecated and\n\ +\ may be removed in a future release.\n\ \ --add-reads <module>=<target-module>(,<target-module>)*\n\ \ updates <module> to read <target-module>, regardless\n\ \ of module declaration. \n\
--- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java Thu May 30 19:51:24 2019 +0200 @@ -222,6 +222,8 @@ Objects.requireNonNull(name); if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); + if (!name.type().isInstance(value)) + throw new IllegalArgumentException("Invalid value '" + value + "'"); synchronized (stateLock) { ensureOpen(); @@ -236,8 +238,6 @@ } if (name == StandardSocketOptions.IP_MULTICAST_IF) { - if (value == null) - throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'"); NetworkInterface interf = (NetworkInterface)value; if (family == StandardProtocolFamily.INET6) { int index = interf.getIndex();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java Thu May 30 19:51:24 2019 +0200 @@ -0,0 +1,1283 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.nio.ch; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketImpl; +import java.net.SocketOption; +import java.net.SocketTimeoutException; +import java.net.StandardProtocolFamily; +import java.net.StandardSocketOptions; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +import jdk.internal.ref.CleanerFactory; +import sun.net.ConnectionResetException; +import sun.net.NetHooks; +import sun.net.PlatformSocketImpl; +import sun.net.ResourceManager; +import sun.net.ext.ExtendedSocketOptions; +import sun.net.util.SocketExceptions; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +/** + * NIO based SocketImpl. + * + * This implementation attempts to be compatible with legacy PlainSocketImpl, + * including behavior and exceptions that are not specified by SocketImpl. + * + * The underlying socket used by this SocketImpl is initially configured + * blocking. If the connect method is used to establish a connection with a + * timeout then the socket is configured non-blocking for the connect attempt, + * and then restored to blocking mode when the connection is established. + * If the accept or read methods are used with a timeout then the socket is + * configured non-blocking and is never restored. When in non-blocking mode, + * operations that don't complete immediately will poll the socket and preserve + * the semantics of blocking operations. + */ + +public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl { + private static final NativeDispatcher nd = new SocketDispatcher(); + + // The maximum number of bytes to read/write per syscall to avoid needing + // a huge buffer from the temporary buffer cache + private static final int MAX_BUFFER_SIZE = 128 * 1024; + + // true if this is a SocketImpl for a ServerSocket + private final boolean server; + + // Lock held when reading (also used when accepting or connecting) + private final ReentrantLock readLock = new ReentrantLock(); + + // Lock held when writing + private final ReentrantLock writeLock = new ReentrantLock(); + + // The stateLock for read/changing state + private final Object stateLock = new Object(); + private static final int ST_NEW = 0; + private static final int ST_UNCONNECTED = 1; + private static final int ST_CONNECTING = 2; + private static final int ST_CONNECTED = 3; + private static final int ST_CLOSING = 4; + private static final int ST_CLOSED = 5; + private volatile int state; // need stateLock to change + + // set by SocketImpl.create, protected by stateLock + private boolean stream; + private FileDescriptorCloser closer; + + // set to true when the socket is in non-blocking mode + private volatile boolean nonBlocking; + + // used by connect/read/write/accept, protected by stateLock + private long readerThread; + private long writerThread; + + // used when SO_REUSEADDR is emulated, protected by stateLock + private boolean isReuseAddress; + + // read or accept timeout in millis + private volatile int timeout; + + // flags to indicate if the connection is shutdown for input and output + private volatile boolean isInputClosed; + private volatile boolean isOutputClosed; + + // used by read to emulate legacy behavior, protected by readLock + private boolean readEOF; + private boolean connectionReset; + + /** + * Creates an instance of this SocketImpl. + * @param server true if this is a SocketImpl for a ServerSocket + */ + public NioSocketImpl(boolean server) { + this.server = server; + } + + /** + * Returns true if the socket is open. + */ + private boolean isOpen() { + return state < ST_CLOSING; + } + + /** + * Throws SocketException if the socket is not open. + */ + private void ensureOpen() throws SocketException { + int state = this.state; + if (state == ST_NEW) + throw new SocketException("Socket not created"); + if (state >= ST_CLOSING) + throw new SocketException("Socket closed"); + } + + /** + * Throws SocketException if the socket is not open and connected. + */ + private void ensureOpenAndConnected() throws SocketException { + int state = this.state; + if (state < ST_CONNECTED) + throw new SocketException("Not connected"); + if (state > ST_CONNECTED) + throw new SocketException("Socket closed"); + } + + /** + * Disables the current thread for scheduling purposes until the socket is + * ready for I/O, or is asynchronously closed, for up to the specified + * waiting time. + * @throws IOException if an I/O error occurs + */ + private void park(FileDescriptor fd, int event, long nanos) throws IOException { + long millis; + if (nanos == 0) { + millis = -1; + } else { + millis = NANOSECONDS.toMillis(nanos); + } + Net.poll(fd, event, millis); + } + + /** + * Disables the current thread for scheduling purposes until the socket is + * ready for I/O or is asynchronously closed. + * @throws IOException if an I/O error occurs + */ + private void park(FileDescriptor fd, int event) throws IOException { + park(fd, event, 0); + } + + /** + * Configures the socket to blocking mode. This method is a no-op if the + * socket is already in blocking mode. + * @throws IOException if closed or there is an I/O error changing the mode + */ + private void configureBlocking(FileDescriptor fd) throws IOException { + assert readLock.isHeldByCurrentThread(); + if (nonBlocking) { + synchronized (stateLock) { + ensureOpen(); + IOUtil.configureBlocking(fd, true); + nonBlocking = false; + } + } + } + + /** + * Configures the socket to non-blocking mode. This method is a no-op if the + * socket is already in non-blocking mode. + * @throws IOException if closed or there is an I/O error changing the mode + */ + private void configureNonBlocking(FileDescriptor fd) throws IOException { + assert readLock.isHeldByCurrentThread(); + if (!nonBlocking) { + synchronized (stateLock) { + ensureOpen(); + IOUtil.configureBlocking(fd, false); + nonBlocking = true; + } + } + } + + /** + * Marks the beginning of a read operation that might block. + * @throws SocketException if the socket is closed or not connected + */ + private FileDescriptor beginRead() throws SocketException { + synchronized (stateLock) { + ensureOpenAndConnected(); + readerThread = NativeThread.current(); + return fd; + } + } + + /** + * Marks the end of a read operation that may have blocked. + * @throws SocketException is the socket is closed + */ + private void endRead(boolean completed) throws SocketException { + synchronized (stateLock) { + readerThread = 0; + int state = this.state; + if (state == ST_CLOSING) + tryFinishClose(); + if (!completed && state >= ST_CLOSING) + throw new SocketException("Socket closed"); + } + } + + /** + * Attempts to read bytes from the socket into the given byte array. + */ + private int tryRead(FileDescriptor fd, byte[] b, int off, int len) + throws IOException + { + ByteBuffer dst = Util.getTemporaryDirectBuffer(len); + assert dst.position() == 0; + try { + int n = nd.read(fd, ((DirectBuffer)dst).address(), len); + if (n > 0) { + dst.get(b, off, n); + } + return n; + } finally { + Util.offerFirstTemporaryDirectBuffer(dst); + } + } + + /** + * Reads bytes from the socket into the given byte array with a timeout. + * @throws SocketTimeoutException if the read timeout elapses + */ + private int timedRead(FileDescriptor fd, byte[] b, int off, int len, long nanos) + throws IOException + { + long startNanos = System.nanoTime(); + int n = tryRead(fd, b, off, len); + while (n == IOStatus.UNAVAILABLE && isOpen()) { + long remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Read timed out"); + } + park(fd, Net.POLLIN, remainingNanos); + n = tryRead(fd, b, off, len); + } + return n; + } + + /** + * Reads bytes from the socket into the given byte array. + * @return the number of bytes read or -1 at EOF + * @throws SocketException if the socket is closed or a socket I/O error occurs + * @throws SocketTimeoutException if the read timeout elapses + */ + private int implRead(byte[] b, int off, int len) throws IOException { + int n = 0; + FileDescriptor fd = beginRead(); + try { + if (connectionReset) + throw new SocketException("Connection reset"); + if (isInputClosed) + return -1; + int timeout = this.timeout; + if (timeout > 0) { + // read with timeout + configureNonBlocking(fd); + n = timedRead(fd, b, off, len, MILLISECONDS.toNanos(timeout)); + } else { + // read, no timeout + n = tryRead(fd, b, off, len); + while (IOStatus.okayToRetry(n) && isOpen()) { + park(fd, Net.POLLIN); + n = tryRead(fd, b, off, len); + } + } + return n; + } catch (SocketTimeoutException e) { + throw e; + } catch (ConnectionResetException e) { + connectionReset = true; + throw new SocketException("Connection reset"); + } catch (IOException ioe) { + throw new SocketException(ioe.getMessage()); + } finally { + endRead(n > 0); + } + } + + /** + * Reads bytes from the socket into the given byte array. + * @return the number of bytes read or -1 at EOF + * @throws IndexOutOfBoundsException if the bound checks fail + * @throws SocketException if the socket is closed or a socket I/O error occurs + * @throws SocketTimeoutException if the read timeout elapses + */ + private int read(byte[] b, int off, int len) throws IOException { + Objects.checkFromIndexSize(off, len, b.length); + if (len == 0) { + return 0; + } else { + readLock.lock(); + try { + // emulate legacy behavior to return -1, even if socket is closed + if (readEOF) + return -1; + // read up to MAX_BUFFER_SIZE bytes + int size = Math.min(len, MAX_BUFFER_SIZE); + int n = implRead(b, off, size); + if (n == -1) + readEOF = true; + return n; + } finally { + readLock.unlock(); + } + } + } + + /** + * Marks the beginning of a write operation that might block. + * @throws SocketException if the socket is closed or not connected + */ + private FileDescriptor beginWrite() throws SocketException { + synchronized (stateLock) { + ensureOpenAndConnected(); + writerThread = NativeThread.current(); + return fd; + } + } + + /** + * Marks the end of a write operation that may have blocked. + * @throws SocketException is the socket is closed + */ + private void endWrite(boolean completed) throws SocketException { + synchronized (stateLock) { + writerThread = 0; + int state = this.state; + if (state == ST_CLOSING) + tryFinishClose(); + if (!completed && state >= ST_CLOSING) + throw new SocketException("Socket closed"); + } + } + + /** + * Attempts to write a sequence of bytes to the socket from the given + * byte array. + */ + private int tryWrite(FileDescriptor fd, byte[] b, int off, int len) + throws IOException + { + ByteBuffer src = Util.getTemporaryDirectBuffer(len); + assert src.position() == 0; + try { + src.put(b, off, len); + return nd.write(fd, ((DirectBuffer)src).address(), len); + } finally { + Util.offerFirstTemporaryDirectBuffer(src); + } + } + + /** + * Writes a sequence of bytes to the socket from the given byte array. + * @return the number of bytes written + * @throws SocketException if the socket is closed or a socket I/O error occurs + */ + private int implWrite(byte[] b, int off, int len) throws IOException { + int n = 0; + FileDescriptor fd = beginWrite(); + try { + n = tryWrite(fd, b, off, len); + while (IOStatus.okayToRetry(n) && isOpen()) { + park(fd, Net.POLLOUT); + n = tryWrite(fd, b, off, len); + } + return n; + } catch (IOException ioe) { + throw new SocketException(ioe.getMessage()); + } finally { + endWrite(n > 0); + } + } + + /** + * Writes a sequence of bytes to the socket from the given byte array. + * @throws SocketException if the socket is closed or a socket I/O error occurs + */ + private void write(byte[] b, int off, int len) throws IOException { + Objects.checkFromIndexSize(off, len, b.length); + if (len > 0) { + writeLock.lock(); + try { + int pos = off; + int end = off + len; + while (pos < end) { + // write up to MAX_BUFFER_SIZE bytes + int size = Math.min((end - pos), MAX_BUFFER_SIZE); + int n = implWrite(b, pos, size); + pos += n; + } + } finally { + writeLock.unlock(); + } + } + } + + /** + * Creates the socket. + * @param stream {@code true} for a streams socket + */ + @Override + protected void create(boolean stream) throws IOException { + synchronized (stateLock) { + if (state != ST_NEW) + throw new IOException("Already created"); + if (!stream) + ResourceManager.beforeUdpCreate(); + FileDescriptor fd; + try { + if (server) { + assert stream; + fd = Net.serverSocket(true); + } else { + fd = Net.socket(stream); + } + } catch (IOException ioe) { + if (!stream) + ResourceManager.afterUdpClose(); + throw ioe; + } + this.fd = fd; + this.stream = stream; + this.closer = FileDescriptorCloser.create(this); + this.state = ST_UNCONNECTED; + } + } + + /** + * Marks the beginning of a connect operation that might block. + * @throws SocketException if the socket is closed or already connected + */ + private FileDescriptor beginConnect(InetAddress address, int port) + throws IOException + { + synchronized (stateLock) { + int state = this.state; + if (state != ST_UNCONNECTED) { + if (state == ST_NEW) + throw new SocketException("Not created"); + if (state == ST_CONNECTING) + throw new SocketException("Connection in progress"); + if (state == ST_CONNECTED) + throw new SocketException("Already connected"); + if (state >= ST_CLOSING) + throw new SocketException("Socket closed"); + assert false; + } + this.state = ST_CONNECTING; + + // invoke beforeTcpConnect hook if not already bound + if (localport == 0) { + NetHooks.beforeTcpConnect(fd, address, port); + } + + // save the remote address/port + this.address = address; + this.port = port; + + readerThread = NativeThread.current(); + return fd; + } + } + + /** + * Marks the end of a connect operation that may have blocked. + * @throws SocketException is the socket is closed + */ + private void endConnect(FileDescriptor fd, boolean completed) throws IOException { + synchronized (stateLock) { + readerThread = 0; + int state = this.state; + if (state == ST_CLOSING) + tryFinishClose(); + if (completed && state == ST_CONNECTING) { + this.state = ST_CONNECTED; + localport = Net.localAddress(fd).getPort(); + } else if (!completed && state >= ST_CLOSING) { + throw new SocketException("Socket closed"); + } + } + } + + /** + * Waits for a connection attempt to finish with a timeout + * @throws SocketTimeoutException if the connect timeout elapses + */ + private boolean timedFinishConnect(FileDescriptor fd, long nanos) throws IOException { + long startNanos = System.nanoTime(); + boolean polled = Net.pollConnectNow(fd); + while (!polled && isOpen()) { + long remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Connect timed out"); + } + park(fd, Net.POLLOUT, remainingNanos); + polled = Net.pollConnectNow(fd); + } + return polled && isOpen(); + } + + /** + * Attempts to establish a connection to the given socket address with a + * timeout. Closes the socket if connection cannot be established. + * @throws IOException if the address is not a resolved InetSocketAddress or + * the connection cannot be established + */ + @Override + protected void connect(SocketAddress remote, int millis) throws IOException { + // SocketImpl connect only specifies IOException + if (!(remote instanceof InetSocketAddress)) + throw new IOException("Unsupported address type"); + InetSocketAddress isa = (InetSocketAddress) remote; + if (isa.isUnresolved()) { + throw new UnknownHostException(isa.getHostName()); + } + + InetAddress address = isa.getAddress(); + if (address.isAnyLocalAddress()) + address = InetAddress.getLocalHost(); + int port = isa.getPort(); + + ReentrantLock connectLock = readLock; + try { + connectLock.lock(); + try { + boolean connected = false; + FileDescriptor fd = beginConnect(address, port); + try { + + // configure socket to non-blocking mode when there is a timeout + if (millis > 0) { + configureNonBlocking(fd); + } + + int n = Net.connect(fd, address, port); + if (n > 0) { + // connection established + connected = true; + } else { + assert IOStatus.okayToRetry(n); + if (millis > 0) { + // finish connect with timeout + long nanos = MILLISECONDS.toNanos(millis); + connected = timedFinishConnect(fd, nanos); + } else { + // finish connect, no timeout + boolean polled = false; + while (!polled && isOpen()) { + park(fd, Net.POLLOUT); + polled = Net.pollConnectNow(fd); + } + connected = polled && isOpen(); + } + } + + // restore socket to blocking mode + if (connected && millis > 0) { + configureBlocking(fd); + } + + } finally { + endConnect(fd, connected); + } + } finally { + connectLock.unlock(); + } + } catch (IOException ioe) { + close(); + throw SocketExceptions.of(ioe, isa); + } + } + + @Override + protected void connect(String host, int port) throws IOException { + connect(new InetSocketAddress(host, port), 0); + } + + @Override + protected void connect(InetAddress address, int port) throws IOException { + connect(new InetSocketAddress(address, port), 0); + } + + @Override + protected void bind(InetAddress host, int port) throws IOException { + synchronized (stateLock) { + ensureOpen(); + if (localport != 0) + throw new SocketException("Already bound"); + NetHooks.beforeTcpBind(fd, host, port); + Net.bind(fd, host, port); + // set the address field to the given host address to keep + // compatibility with PlainSocketImpl. When binding to 0.0.0.0 + // then the actual local address will be ::0 when IPv6 is enabled. + address = host; + localport = Net.localAddress(fd).getPort(); + } + } + + @Override + protected void listen(int backlog) throws IOException { + synchronized (stateLock) { + ensureOpen(); + if (localport == 0) + throw new SocketException("Not bound"); + Net.listen(fd, backlog < 1 ? 50 : backlog); + } + } + + /** + * Marks the beginning of an accept operation that might block. + * @throws SocketException if the socket is closed + */ + private FileDescriptor beginAccept() throws SocketException { + synchronized (stateLock) { + ensureOpen(); + if (!stream) + throw new SocketException("Not a stream socket"); + if (localport == 0) + throw new SocketException("Not bound"); + readerThread = NativeThread.current(); + return fd; + } + } + + /** + * Marks the end of an accept operation that may have blocked. + * @throws SocketException is the socket is closed + */ + private void endAccept(boolean completed) throws SocketException { + synchronized (stateLock) { + int state = this.state; + readerThread = 0; + if (state == ST_CLOSING) + tryFinishClose(); + if (!completed && state >= ST_CLOSING) + throw new SocketException("Socket closed"); + } + } + + /** + * Accepts a new connection with a timeout. + * @throws SocketTimeoutException if the accept timeout elapses + */ + private int timedAccept(FileDescriptor fd, + FileDescriptor newfd, + InetSocketAddress[] isaa, + long nanos) + throws IOException + { + long startNanos = System.nanoTime(); + int n = Net.accept(fd, newfd, isaa); + while (n == IOStatus.UNAVAILABLE && isOpen()) { + long remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Accept timed out"); + } + park(fd, Net.POLLIN, remainingNanos); + n = Net.accept(fd, newfd, isaa); + } + return n; + } + + /** + * Accepts a new connection so that the given SocketImpl is connected to + * the peer. The SocketImpl must be a newly created NioSocketImpl. + */ + @Override + protected void accept(SocketImpl si) throws IOException { + NioSocketImpl nsi = (NioSocketImpl) si; + if (nsi.state != ST_NEW) + throw new SocketException("Not a newly created SocketImpl"); + + FileDescriptor newfd = new FileDescriptor(); + InetSocketAddress[] isaa = new InetSocketAddress[1]; + + // acquire the lock, adjusting the timeout for cases where several + // threads are accepting connections and there is a timeout set + ReentrantLock acceptLock = readLock; + int timeout = this.timeout; + long remainingNanos = 0; + if (timeout > 0) { + remainingNanos = tryLock(acceptLock, timeout, MILLISECONDS); + if (remainingNanos <= 0) { + assert !acceptLock.isHeldByCurrentThread(); + throw new SocketTimeoutException("Accept timed out"); + } + } else { + acceptLock.lock(); + } + + // accept a connection + try { + int n = 0; + FileDescriptor fd = beginAccept(); + try { + if (remainingNanos > 0) { + // accept with timeout + configureNonBlocking(fd); + n = timedAccept(fd, newfd, isaa, remainingNanos); + } else { + // accept, no timeout + n = Net.accept(fd, newfd, isaa); + while (IOStatus.okayToRetry(n) && isOpen()) { + park(fd, Net.POLLIN); + n = Net.accept(fd, newfd, isaa); + } + } + } finally { + endAccept(n > 0); + assert IOStatus.check(n); + } + } finally { + acceptLock.unlock(); + } + + // get local address and configure accepted socket to blocking mode + InetSocketAddress localAddress; + try { + localAddress = Net.localAddress(newfd); + IOUtil.configureBlocking(newfd, true); + } catch (IOException ioe) { + nd.close(newfd); + throw ioe; + } + + // set the fields + synchronized (nsi.stateLock) { + nsi.fd = newfd; + nsi.stream = true; + nsi.closer = FileDescriptorCloser.create(nsi); + nsi.localport = localAddress.getPort(); + nsi.address = isaa[0].getAddress(); + nsi.port = isaa[0].getPort(); + nsi.state = ST_CONNECTED; + } + } + + @Override + protected InputStream getInputStream() { + return new InputStream() { + @Override + public int read() throws IOException { + byte[] a = new byte[1]; + int n = read(a, 0, 1); + return (n > 0) ? (a[0] & 0xff) : -1; + } + @Override + public int read(byte[] b, int off, int len) throws IOException { + return NioSocketImpl.this.read(b, off, len); + } + @Override + public int available() throws IOException { + return NioSocketImpl.this.available(); + } + @Override + public void close() throws IOException { + NioSocketImpl.this.close(); + } + }; + } + + @Override + protected OutputStream getOutputStream() { + return new OutputStream() { + @Override + public void write(int b) throws IOException { + byte[] a = new byte[]{(byte) b}; + write(a, 0, 1); + } + @Override + public void write(byte[] b, int off, int len) throws IOException { + NioSocketImpl.this.write(b, off, len); + } + @Override + public void close() throws IOException { + NioSocketImpl.this.close(); + } + }; + } + + @Override + protected int available() throws IOException { + synchronized (stateLock) { + ensureOpenAndConnected(); + if (isInputClosed) { + return 0; + } else { + return Net.available(fd); + } + } + } + + /** + * Closes the socket if there are no I/O operations in progress. + */ + private boolean tryClose() throws IOException { + assert Thread.holdsLock(stateLock) && state == ST_CLOSING; + if (readerThread == 0 && writerThread == 0) { + try { + closer.run(); + } catch (UncheckedIOException ioe) { + throw ioe.getCause(); + } finally { + state = ST_CLOSED; + } + return true; + } else { + return false; + } + } + + /** + * Invokes tryClose to attempt to close the socket. + * + * This method is used for deferred closing by I/O operations. + */ + private void tryFinishClose() { + try { + tryClose(); + } catch (IOException ignore) { } + } + + /** + * Closes the socket. If there are I/O operations in progress then the + * socket is pre-closed and the threads are signalled. The socket will be + * closed when the last I/O operation aborts. + */ + @Override + protected void close() throws IOException { + synchronized (stateLock) { + int state = this.state; + if (state >= ST_CLOSING) + return; + if (state == ST_NEW) { + // stillborn + this.state = ST_CLOSED; + return; + } + this.state = ST_CLOSING; + + // shutdown output when linger interval not set to 0 + try { + var SO_LINGER = StandardSocketOptions.SO_LINGER; + if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) { + Net.shutdown(fd, Net.SHUT_WR); + } + } catch (IOException ignore) { } + + // attempt to close the socket. If there are I/O operations in progress + // then the socket is pre-closed and the thread(s) signalled. The + // last thread will close the file descriptor. + if (!tryClose()) { + nd.preClose(fd); + long reader = readerThread; + if (reader != 0) + NativeThread.signal(reader); + long writer = writerThread; + if (writer != 0) + NativeThread.signal(writer); + } + } + } + + // the socket options supported by client and server sockets + private static volatile Set<SocketOption<?>> clientSocketOptions; + private static volatile Set<SocketOption<?>> serverSocketOptions; + + @Override + protected Set<SocketOption<?>> supportedOptions() { + Set<SocketOption<?>> options = (server) ? serverSocketOptions : clientSocketOptions; + if (options == null) { + options = new HashSet<>(); + options.add(StandardSocketOptions.SO_RCVBUF); + options.add(StandardSocketOptions.SO_REUSEADDR); + if (server) { + // IP_TOS added for server socket to maintain compatibility + options.add(StandardSocketOptions.IP_TOS); + options.addAll(ExtendedSocketOptions.serverSocketOptions()); + } else { + options.add(StandardSocketOptions.IP_TOS); + options.add(StandardSocketOptions.SO_KEEPALIVE); + options.add(StandardSocketOptions.SO_SNDBUF); + options.add(StandardSocketOptions.SO_LINGER); + options.add(StandardSocketOptions.TCP_NODELAY); + options.addAll(ExtendedSocketOptions.clientSocketOptions()); + } + if (Net.isReusePortAvailable()) + options.add(StandardSocketOptions.SO_REUSEPORT); + options = Collections.unmodifiableSet(options); + if (server) { + serverSocketOptions = options; + } else { + clientSocketOptions = options; + } + } + return options; + } + + @Override + protected <T> void setOption(SocketOption<T> opt, T value) throws IOException { + if (!supportedOptions().contains(opt)) + throw new UnsupportedOperationException("'" + opt + "' not supported"); + if (!opt.type().isInstance(value)) + throw new IllegalArgumentException("Invalid value '" + value + "'"); + synchronized (stateLock) { + ensureOpen(); + if (opt == StandardSocketOptions.IP_TOS) { + // maps to IP_TOS or IPV6_TCLASS + Net.setSocketOption(fd, family(), opt, value); + } else if (opt == StandardSocketOptions.SO_REUSEADDR) { + boolean b = (boolean) value; + if (Net.useExclusiveBind()) { + isReuseAddress = b; + } else { + Net.setSocketOption(fd, opt, b); + } + } else { + // option does not need special handling + Net.setSocketOption(fd, opt, value); + } + } + } + + @SuppressWarnings("unchecked") + protected <T> T getOption(SocketOption<T> opt) throws IOException { + if (!supportedOptions().contains(opt)) + throw new UnsupportedOperationException("'" + opt + "' not supported"); + synchronized (stateLock) { + ensureOpen(); + if (opt == StandardSocketOptions.IP_TOS) { + return (T) Net.getSocketOption(fd, family(), opt); + } else if (opt == StandardSocketOptions.SO_REUSEADDR) { + if (Net.useExclusiveBind()) { + return (T) Boolean.valueOf(isReuseAddress); + } else { + return (T) Net.getSocketOption(fd, opt); + } + } else { + // option does not need special handling + return (T) Net.getSocketOption(fd, opt); + } + } + } + + private boolean booleanValue(Object value, String desc) throws SocketException { + if (!(value instanceof Boolean)) + throw new SocketException("Bad value for " + desc); + return (boolean) value; + } + + private int intValue(Object value, String desc) throws SocketException { + if (!(value instanceof Integer)) + throw new SocketException("Bad value for " + desc); + return (int) value; + } + + @Override + public void setOption(int opt, Object value) throws SocketException { + synchronized (stateLock) { + ensureOpen(); + try { + switch (opt) { + case SO_LINGER: { + // the value is "false" to disable, or linger interval to enable + int i; + if (value instanceof Boolean && ((boolean) value) == false) { + i = -1; + } else { + i = intValue(value, "SO_LINGER"); + } + Net.setSocketOption(fd, StandardSocketOptions.SO_LINGER, i); + break; + } + case SO_TIMEOUT: { + int i = intValue(value, "SO_TIMEOUT"); + if (i < 0) + throw new IllegalArgumentException("timeout < 0"); + timeout = i; + break; + } + case IP_TOS: { + int i = intValue(value, "IP_TOS"); + Net.setSocketOption(fd, family(), StandardSocketOptions.IP_TOS, i); + break; + } + case TCP_NODELAY: { + boolean b = booleanValue(value, "TCP_NODELAY"); + Net.setSocketOption(fd, StandardSocketOptions.TCP_NODELAY, b); + break; + } + case SO_SNDBUF: { + int i = intValue(value, "SO_SNDBUF"); + if (i <= 0) + throw new SocketException("SO_SNDBUF <= 0"); + Net.setSocketOption(fd, StandardSocketOptions.SO_SNDBUF, i); + break; + } + case SO_RCVBUF: { + int i = intValue(value, "SO_RCVBUF"); + if (i <= 0) + throw new SocketException("SO_RCVBUF <= 0"); + Net.setSocketOption(fd, StandardSocketOptions.SO_RCVBUF, i); + break; + } + case SO_KEEPALIVE: { + boolean b = booleanValue(value, "SO_KEEPALIVE"); + Net.setSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE, b); + break; + } + case SO_OOBINLINE: { + boolean b = booleanValue(value, "SO_OOBINLINE"); + Net.setSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE, b); + break; + } + case SO_REUSEADDR: { + boolean b = booleanValue(value, "SO_REUSEADDR"); + if (Net.useExclusiveBind()) { + isReuseAddress = b; + } else { + Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEADDR, b); + } + break; + } + case SO_REUSEPORT: { + if (!Net.isReusePortAvailable()) + throw new SocketException("SO_REUSEPORT not supported"); + boolean b = booleanValue(value, "SO_REUSEPORT"); + Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEPORT, b); + break; + } + default: + throw new SocketException("Unknown option " + opt); + } + } catch (SocketException e) { + throw e; + } catch (IllegalArgumentException | IOException e) { + throw new SocketException(e.getMessage()); + } + } + } + + @Override + public Object getOption(int opt) throws SocketException { + synchronized (stateLock) { + ensureOpen(); + try { + switch (opt) { + case SO_TIMEOUT: + return timeout; + case TCP_NODELAY: + return Net.getSocketOption(fd, StandardSocketOptions.TCP_NODELAY); + case SO_OOBINLINE: + return Net.getSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE); + case SO_LINGER: { + // return "false" when disabled, linger interval when enabled + int i = (int) Net.getSocketOption(fd, StandardSocketOptions.SO_LINGER); + if (i == -1) { + return Boolean.FALSE; + } else { + return i; + } + } + case SO_REUSEADDR: + if (Net.useExclusiveBind()) { + return isReuseAddress; + } else { + return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEADDR); + } + case SO_BINDADDR: + return Net.localAddress(fd).getAddress(); + case SO_SNDBUF: + return Net.getSocketOption(fd, StandardSocketOptions.SO_SNDBUF); + case SO_RCVBUF: + return Net.getSocketOption(fd, StandardSocketOptions.SO_RCVBUF); + case IP_TOS: + return Net.getSocketOption(fd, family(), StandardSocketOptions.IP_TOS); + case SO_KEEPALIVE: + return Net.getSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE); + case SO_REUSEPORT: + if (!Net.isReusePortAvailable()) + throw new SocketException("SO_REUSEPORT not supported"); + return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEPORT); + default: + throw new SocketException("Unknown option " + opt); + } + } catch (SocketException e) { + throw e; + } catch (IllegalArgumentException | IOException e) { + throw new SocketException(e.getMessage()); + } + } + } + + @Override + protected void shutdownInput() throws IOException { + synchronized (stateLock) { + ensureOpenAndConnected(); + if (!isInputClosed) { + Net.shutdown(fd, Net.SHUT_RD); + isInputClosed = true; + } + } + } + + @Override + protected void shutdownOutput() throws IOException { + synchronized (stateLock) { + ensureOpenAndConnected(); + if (!isOutputClosed) { + Net.shutdown(fd, Net.SHUT_WR); + isOutputClosed = true; + } + } + } + + @Override + protected boolean supportsUrgentData() { + return true; + } + + @Override + protected void sendUrgentData(int data) throws IOException { + writeLock.lock(); + try { + int n = 0; + FileDescriptor fd = beginWrite(); + try { + do { + n = Net.sendOOB(fd, (byte) data); + } while (n == IOStatus.INTERRUPTED && isOpen()); + if (n == IOStatus.UNAVAILABLE) { + throw new SocketException("No buffer space available"); + } + } finally { + endWrite(n > 0); + } + } finally { + writeLock.unlock(); + } + } + + /** + * A task that closes a SocketImpl's file descriptor. The task runs when the + * SocketImpl is explicitly closed and when the SocketImpl becomes phantom + * reachable. + */ + private static class FileDescriptorCloser implements Runnable { + private static final VarHandle CLOSED; + static { + try { + MethodHandles.Lookup l = MethodHandles.lookup(); + CLOSED = l.findVarHandle(FileDescriptorCloser.class, + "closed", + boolean.class); + } catch (Exception e) { + throw new InternalError(e); + } + } + + private final FileDescriptor fd; + private final boolean stream; + private volatile boolean closed; + + FileDescriptorCloser(FileDescriptor fd, boolean stream) { + this.fd = fd; + this.stream = stream; + } + + static FileDescriptorCloser create(NioSocketImpl impl) { + assert Thread.holdsLock(impl.stateLock); + var closer = new FileDescriptorCloser(impl.fd, impl.stream); + CleanerFactory.cleaner().register(impl, closer); + return closer; + } + + @Override + public void run() { + if (CLOSED.compareAndSet(this, false, true)) { + try { + nd.close(fd); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } finally { + if (!stream) { + // decrement + ResourceManager.afterUdpClose(); + } + } + } + } + } + + /** + * Attempts to acquire the given lock within the given waiting time. + * @return the remaining time in nanoseconds when the lock is acquired, zero + * or less if the lock was not acquired before the timeout expired + */ + private static long tryLock(ReentrantLock lock, long timeout, TimeUnit unit) { + assert timeout > 0; + boolean interrupted = false; + long nanos = NANOSECONDS.convert(timeout, unit); + long remainingNanos = nanos; + long startNanos = System.nanoTime(); + boolean acquired = false; + while (!acquired && (remainingNanos > 0)) { + try { + acquired = lock.tryLock(remainingNanos, NANOSECONDS); + } catch (InterruptedException e) { + interrupted = true; + } + remainingNanos = nanos - (System.nanoTime() - startNanos); + } + if (acquired && remainingNanos <= 0L) + lock.unlock(); // release lock if timeout has expired + if (interrupted) + Thread.currentThread().interrupt(); + return remainingNanos; + } + + /** + * Returns the socket protocol family. + */ + private static ProtocolFamily family() { + if (Net.isIPv6Available()) { + return StandardProtocolFamily.INET6; + } else { + return StandardProtocolFamily.INET; + } + } +}
--- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu May 30 19:51:24 2019 +0200 @@ -147,6 +147,9 @@ Objects.requireNonNull(name); if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); + if (!name.type().isInstance(value)) + throw new IllegalArgumentException("Invalid value '" + value + "'"); + synchronized (stateLock) { ensureOpen();
--- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Thu May 30 19:51:24 2019 +0200 @@ -218,6 +218,8 @@ Objects.requireNonNull(name); if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); + if (!name.type().isInstance(value)) + throw new IllegalArgumentException("Invalid value '" + value + "'"); synchronized (stateLock) { ensureOpen();
--- a/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -393,29 +393,22 @@ return (TypeVariable)getType(); } - // For toString, the declaration of a type variable should - // including information about its bounds, etc. However, the + // The declaration of a type variable should + // include information about its bounds, etc. However, the // use of a type variable should not. For that reason, it is - // acceptable for the toString implementation of + // acceptable for the toString and hashCode implementations of // AnnotatedTypeVariableImpl to use the inherited - // implementation from AnnotatedTypeBaseImpl. + // implementations from AnnotatedTypeBaseImpl. @Override public boolean equals(Object o) { if (o instanceof AnnotatedTypeVariable) { AnnotatedTypeVariable that = (AnnotatedTypeVariable) o; - return equalsTypeAndAnnotations(that) && - Arrays.equals(getAnnotatedBounds(), that.getAnnotatedBounds()); + return equalsTypeAndAnnotations(that); } else { return false; } } - - @Override - public int hashCode() { - return baseHashCode() ^ - Objects.hash((Object[])getAnnotatedBounds()); - } } private static final class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl
--- a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java Thu May 30 19:51:24 2019 +0200 @@ -31,6 +31,7 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; +import java.security.NoSuchAlgorithmException; import java.security.PrivilegedAction; import java.security.SecureRandom; import java.security.Security; @@ -42,6 +43,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; import javax.crypto.spec.GCMParameterSpec; @@ -491,16 +493,31 @@ // availability of this bulk cipher // - // We assume all supported ciphers are always available since they are - // shipped with the SunJCE provider. However, AES/256 is unavailable - // when the default JCE policy jurisdiction files are installed because - // of key length restrictions. - this.isAvailable = allowed && isUnlimited(keySize, transformation); + // AES/256 is unavailable when the default JCE policy jurisdiction files + // are installed because of key length restrictions. + this.isAvailable = allowed && isUnlimited(keySize, transformation) && + isTransformationAvailable(transformation); this.readCipherGenerators = readCipherGenerators; this.writeCipherGenerators = writeCipherGenerators; } + private static boolean isTransformationAvailable(String transformation) { + if (transformation.equals("NULL")) { + return true; + } + try { + Cipher.getInstance(transformation); + return true; + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.fine("Transformation " + transformation + " is" + + " not available."); + } + } + return false; + } + SSLReadCipher createReadCipher(Authenticator authenticator, ProtocolVersion protocolVersion, SecretKey key, IvParameterSpec iv,
--- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java Thu May 30 19:51:24 2019 +0200 @@ -379,7 +379,8 @@ boolean isSupported = false; for (ProtocolVersion protocol : protocols) { - if (!suite.supports(protocol)) { + if (!suite.supports(protocol) || + !suite.bulkCipher.isAvailable()) { continue; }
--- a/src/java.base/share/conf/security/java.security Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/conf/security/java.security Thu May 30 19:51:24 2019 +0200 @@ -1022,27 +1022,6 @@ # java.rmi.dgc.Lease;\ # maxdepth=5;maxarray=10000 -# CORBA ORBIorTypeCheckRegistryFilter -# Type check enhancement for ORB::string_to_object processing -# -# An IOR type check filter, if configured, is used by an ORB during -# an ORB::string_to_object invocation to check the veracity of the type encoded -# in the ior string. -# -# The filter pattern consists of a semi-colon separated list of class names. -# The configured list contains the binary class names of the IDL interface types -# corresponding to the IDL stub class to be instantiated. -# As such, a filter specifies a list of IDL stub classes that will be -# allowed by an ORB when an ORB::string_to_object is invoked. -# It is used to specify a white list configuration of acceptable -# IDL stub types which may be contained in a stringified IOR -# parameter passed as input to an ORB::string_to_object method. -# -# Note: This property is currently used by the JDK Reference implementation. -# It is not guaranteed to be examined and used by other implementations. -# -#com.sun.CORBA.ORBIorTypeCheckRegistryFilter=binary_class_name;binary_class_name - # # JCEKS Encrypted Key Serial Filter #
--- a/src/java.base/share/man/java.1 Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/man/java.1 Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ '\" t -.\" Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. .\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. .\" .\" This code is free software; you can redistribute it and/or modify it @@ -1162,6 +1162,8 @@ none .RS 4 Do not verify the bytecode\&. This reduces startup time and also reduces the protection provided by Java\&. +.sp +This option is deprecated and may be removed in a future release. .RE .PP remote
--- a/src/java.base/share/native/libjli/java.c Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/share/native/libjli/java.c Thu May 30 19:51:24 2019 +0200 @@ -1437,6 +1437,10 @@ } else if (JLI_StrCmp(arg, "-verifyremote") == 0) { AddOption("-Xverify:remote", NULL); } else if (JLI_StrCmp(arg, "-noverify") == 0) { + /* + * Note that no 'deprecated' message is needed here because the VM + * issues 'deprecated' messages for -noverify and -Xverify:none. + */ AddOption("-Xverify:none", NULL); } else if (JLI_StrCCmp(arg, "-ss") == 0 || JLI_StrCCmp(arg, "-oss") == 0 ||
--- a/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java Thu May 30 19:51:24 2019 +0200 @@ -41,46 +41,6 @@ init(); } - static final ExtendedSocketOptions extendedOptions = - ExtendedSocketOptions.getInstance(); - - protected <T> void setOption(SocketOption<T> name, T value) throws IOException { - if (isClosed()) { - throw new SocketException("Socket closed"); - } - if (supportedOptions().contains(name)) { - if (extendedOptions.isOptionSupported(name)) { - extendedOptions.setOption(fd, name, value); - } else { - super.setOption(name, value); - } - } else { - throw new UnsupportedOperationException("unsupported option"); - } - } - - @SuppressWarnings("unchecked") - protected <T> T getOption(SocketOption<T> name) throws IOException { - if (isClosed()) { - throw new SocketException("Socket closed"); - } - if (supportedOptions().contains(name)) { - if (extendedOptions.isOptionSupported(name)) { - return (T) extendedOptions.getOption(fd, name); - } else { - return super.getOption(name); - } - } else { - throw new UnsupportedOperationException("unsupported option"); - } - } - - protected Set<SocketOption<?>> supportedOptions() { - HashSet<SocketOption<?>> options = new HashSet<>(super.supportedOptions()); - options.addAll(ExtendedSocketOptions.datagramSocketOptions()); - return options; - } - protected void socketSetOption(int opt, Object val) throws SocketException { if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
--- a/src/java.base/unix/classes/java/net/PlainSocketImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.base/unix/classes/java/net/PlainSocketImpl.java Thu May 30 19:51:24 2019 +0200 @@ -25,7 +25,6 @@ package java.net; import java.io.IOException; -import java.io.FileDescriptor; import java.util.Set; import java.util.HashSet; import sun.net.ext.ExtendedSocketOptions; @@ -49,50 +48,6 @@ super(isServer); } - static final ExtendedSocketOptions extendedOptions = - ExtendedSocketOptions.getInstance(); - - protected <T> void setOption(SocketOption<T> name, T value) throws IOException { - if (isClosedOrPending()) { - throw new SocketException("Socket closed"); - } - if (supportedOptions().contains(name)) { - if (extendedOptions.isOptionSupported(name)) { - extendedOptions.setOption(fd, name, value); - } else { - super.setOption(name, value); - } - } else { - throw new UnsupportedOperationException("unsupported option"); - } - } - - @SuppressWarnings("unchecked") - protected <T> T getOption(SocketOption<T> name) throws IOException { - if (isClosedOrPending()) { - throw new SocketException("Socket closed"); - } - if (supportedOptions().contains(name)) { - if (extendedOptions.isOptionSupported(name)) { - return (T) extendedOptions.getOption(fd, name); - } else { - return super.getOption(name); - } - } else { - throw new UnsupportedOperationException("unsupported option"); - } - } - - protected Set<SocketOption<?>> supportedOptions() { - HashSet<SocketOption<?>> options = new HashSet<>(super.supportedOptions()); - if (isServer) { - options.addAll(ExtendedSocketOptions.serverSocketOptions()); - } else { - options.addAll(ExtendedSocketOptions.clientSocketOptions()); - } - return options; - } - protected void socketSetOption(int opt, boolean b, Object val) throws SocketException { if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
--- a/src/java.management/share/classes/java/lang/management/ManagementFactory.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.management/share/classes/java/lang/management/ManagementFactory.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -872,12 +872,13 @@ public static Set<Class<? extends PlatformManagedObject>> getPlatformManagementInterfaces() { - return platformComponents() + // local variable required here; see JDK-8223553 + Stream<Class<? extends PlatformManagedObject>> pmos = platformComponents() .stream() .flatMap(pc -> pc.mbeanInterfaces().stream()) .filter(clazz -> PlatformManagedObject.class.isAssignableFrom(clazz)) - .map(clazz -> clazz.asSubclass(PlatformManagedObject.class)) - .collect(Collectors.toSet()); + .map(clazz -> clazz.asSubclass(PlatformManagedObject.class)); + return pmos.collect(Collectors.toSet()); } private static final String NOTIF_EMITTER =
--- a/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.naming/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreImpl.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,8 +62,6 @@ private static final Debug debug = Debug.getInstance("certpath"); - private final static boolean DEBUG = false; - /** * LDAP attribute identifiers. */ @@ -72,7 +70,6 @@ private static final String CROSS_CERT = "crossCertificatePair;binary"; private static final String CRL = "certificateRevocationList;binary"; private static final String ARL = "authorityRevocationList;binary"; - private static final String DELTA_CRL = "deltaRevocationList;binary"; // Constants for various empty values private final static String[] STRING0 = new String[0]; @@ -113,6 +110,7 @@ * their binary stored form. */ private CertificateFactory cf; + /** * The JNDI directory context. */ @@ -241,10 +239,6 @@ return name; } - String getName() { - return name; - } - void addRequestedAttribute(String attrId) { if (valueMap != null) { throw new IllegalStateException("Request already sent"); @@ -260,9 +254,9 @@ * @throws NamingException if a naming exception occurs */ byte[][] getValues(String attrId) throws NamingException { - if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) { - System.out.println("Cache hits: " + cacheHits + "; misses: " - + cacheMisses); + if (debug != null && Debug.isVerbose() && ((cacheHits + cacheMisses) % 50 == 0)) { + debug.println("LDAPRequest Cache hits: " + cacheHits + + "; misses: " + cacheMisses); } String cacheKey = name + "|" + attrId; byte[][] values = valueCache.get(cacheKey); @@ -294,11 +288,11 @@ if (valueMap != null) { return valueMap; } - if (DEBUG) { - System.out.println("Request: " + name + ":" + requestedAttributes); + if (debug != null && Debug.isVerbose()) { + debug.println("LDAPRequest: " + name + ":" + requestedAttributes); requests++; if (requests % 5 == 0) { - System.out.println("LDAP requests: " + requests); + debug.println("LDAP requests: " + requests); } } valueMap = new HashMap<>(8);
--- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java Thu May 30 19:51:24 2019 +0200 @@ -26,14 +26,15 @@ package jdk.internal.net.http; import java.io.IOException; +import java.net.http.HttpClient; +import java.net.http.HttpResponse; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; -import java.util.function.Function; -import java.net.http.HttpClient; -import java.net.http.HttpResponse; + import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.MinimalFuture; import jdk.internal.net.http.common.Utils; + import static java.net.http.HttpClient.Version.HTTP_1_1; /** @@ -92,8 +93,10 @@ CompletableFuture<Http2Connection> c2f = c2.getConnectionFor(request, exchange); if (debug.on()) debug.log("get: Trying to get HTTP/2 connection"); - return c2f.handle((h2c, t) -> createExchangeImpl(h2c, t, exchange, connection)) - .thenCompose(Function.identity()); + // local variable required here; see JDK-8223553 + CompletableFuture<CompletableFuture<? extends ExchangeImpl<U>>> fxi = + c2f.handle((h2c, t) -> createExchangeImpl(h2c, t, exchange, connection)); + return fxi.thenCompose(x->x); } }
--- a/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Server.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -195,8 +195,13 @@ switch (step) { case 1: if (response.length != 0) { - throw new SaslException( - "DIGEST-MD5 must not have an initial response"); + // We do not support "subsequent authentication" (client + // initial response). According to + // https://tools.ietf.org/html/rfc2831#section-2.2 + // If the server does not support subsequent authentication, + // then it sends a "digest-challenge", and authentication + // proceeds as in initial authentication. + logger.log(Level.FINE, "Ignoring initial response"); } /* Generate first challenge */
--- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/CanonicalizationMethod.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/CanonicalizationMethod.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,24 @@ "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"; /** + * The <a href="https://www.w3.org/TR/xml-c14n11/">Canonical XML 1.1 + * (without comments)</a> canonicalization method algorithm URI. + * + * @since 13 + */ + final static String INCLUSIVE_11 = "http://www.w3.org/2006/12/xml-c14n11"; + + /** + * The <a href="https://www.w3.org/TR/xml-c14n11/#WithComments"> + * Canonical XML 1.1 with comments</a> canonicalization method algorithm + * URI. + * + * @since 13 + */ + final static String INCLUSIVE_11_WITH_COMMENTS = + "http://www.w3.org/2006/12/xml-c14n11#WithComments"; + + /** * Returns the algorithm-specific input parameters associated with this * <code>CanonicalizationMethod</code>. *
--- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,9 +141,18 @@ * may be different than the order of providers returned by * {@link Security#getProviders() Security.getProviders()}. * - * @param algorithm the URI of the algorithm + * @param algorithm the URI of the algorithm. See the + * {@code TransformService} section in the + * <a href= + * "{@docRoot}/../specs/security/standard-names.html#xml-signature-transform-transformservice-algorithms"> + * Java Security Standard Algorithm Names Specification</a> for a list of + * standard transform algorithms. * @param mechanismType the type of the XML processing mechanism and - * representation + * representation. See the {@code TransformService} section in the + * <a href= + * "{@docRoot}/../specs/security/standard-names.html#xml-signature-xmlsignaturefactorykeyinfofactorytransformservice-mechanisms"> + * Java Security Standard Algorithm Names Specification</a> for a list of + * standard mechanism types. * @return a new <code>TransformService</code> * @throws NullPointerException if <code>algorithm</code> or * <code>mechanismType</code> is <code>null</code> @@ -193,9 +202,18 @@ * <code>Provider</code> object does not have to be registered in the * provider list. * - * @param algorithm the URI of the algorithm + * @param algorithm the URI of the algorithm. See the + * {@code TransformService} section in the + * <a href= + * "{@docRoot}/../specs/security/standard-names.html#xml-signature-transform-transformservice-algorithms"> + * Java Security Standard Algorithm Names Specification</a> for a list of + * standard transform algorithms. * @param mechanismType the type of the XML processing mechanism and - * representation + * representation. See the {@code TransformService} section in the + * <a href= + * "{@docRoot}/../specs/security/standard-names.html#xml-signature-xmlsignaturefactorykeyinfofactorytransformservice-mechanisms"> + * Java Security Standard Algorithm Names Specification</a> for a list of + * standard mechanism types. * @param provider the <code>Provider</code> object * @return a new <code>TransformService</code> * @throws NullPointerException if <code>provider</code>, @@ -246,9 +264,18 @@ * <p>Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * - * @param algorithm the URI of the algorithm + * @param algorithm the URI of the algorithm. See the + * {@code TransformService} section in the + * <a href= + * "{@docRoot}/../specs/security/standard-names.html#xml-signature-transform-transformservice-algorithms"> + * Java Security Standard Algorithm Names Specification</a> for a list of + * standard transform algorithms. * @param mechanismType the type of the XML processing mechanism and - * representation + * representation. See the {@code TransformService} section in the + * <a href= + * "{@docRoot}/../specs/security/standard-names.html#xml-signature-xmlsignaturefactorykeyinfofactorytransformservice-mechanisms"> + * Java Security Standard Algorithm Names Specification</a> for a list of + * standard mechanism types. * @param provider the string name of the provider * @return a new <code>TransformService</code> * @throws NoSuchProviderException if the specified provider is not
--- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyValue.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyValue.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package javax.xml.crypto.dsig.keyinfo; import java.security.KeyException; -import java.security.KeyStore; import java.security.PublicKey; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.RSAPublicKey; @@ -47,6 +46,8 @@ * <choice> * <element ref="ds:DSAKeyValue"/> * <element ref="ds:RSAKeyValue"/> + * <!-- <element ref="dsig11:ECKeyValue"/> --> + * <!-- ECC keys (XMLDsig 1.1) will use the any element --> * <any namespace="##other" processContents="lax"/> * </choice> * </complexType> @@ -75,8 +76,30 @@ * <element name="Exponent" type="ds:CryptoBinary"/> * </sequence> * </complexType> + * + * <complexType name="ECKeyValueType"> + * <sequence> + * <choice> + * <element name="ECParameters" type="dsig11:ECParametersType" /> + * <element name="NamedCurve" type="dsig11:NamedCurveType" /> + * </choice> + * <element name="PublicKey" type="dsig11:ECPointType" /> + * </sequence> + * <attribute name="Id" type="ID" use="optional" /> + * </complexType> + * + * <complexType name="NamedCurveType"> + * <attribute name="URI" type="anyURI" use="required" /> + * </complexType> + * + * <simpleType name="ECPointType"> + * <restriction base="ds:CryptoBinary" /> + * </simpleType> * </pre> - * A <code>KeyValue</code> instance may be created by invoking the + * See section 4.5.2.3.1 of the W3C Recommendation for the definition + * of ECParametersType. + * + * <p>A <code>KeyValue</code> instance may be created by invoking the * {@link KeyInfoFactory#newKeyValue newKeyValue} method of the * {@link KeyInfoFactory} class, and passing it a {@link * java.security.PublicKey} representing the value of the public key. Here is @@ -124,6 +147,16 @@ "http://www.w3.org/2000/09/xmldsig#RSAKeyValue"; /** + * URI identifying the EC KeyValue KeyInfo type: + * http://www.w3.org/2009/xmldsig11#ECKeyValue. This can be specified as + * the value of the <code>type</code> parameter of the + * {@link RetrievalMethod} class to describe a remote + * <code>ECKeyValue</code> structure. + */ + final static String EC_TYPE = + "http://www.w3.org/2009/xmldsig11#ECKeyValue"; + + /** * Returns the public key of this <code>KeyValue</code>. * * @return the public key of this <code>KeyValue</code>
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DeferredDocumentImpl.java Thu May 23 22:14:23 2019 +0200 +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DeferredDocumentImpl.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -42,7 +42,7 @@ * @xerces.internal * * @since PR-DOM-Level-1-19980818. - * @LastModified: Oct 2017 + * @LastModified: May 2019 */ public class DeferredDocumentImpl extends DocumentImpl @@ -69,7 +69,7 @@ // protected /** Chunk shift. */ - protected static final int CHUNK_SHIFT = 11; // 2^11 = 2k + protected static final int CHUNK_SHIFT = 8; // 2^8 = 256 /** Chunk size. */ protected static final int CHUNK_SIZE = (1 << CHUNK_SHIFT); @@ -78,7 +78,7 @@ protected static final int CHUNK_MASK = CHUNK_SIZE - 1; /** Initial chunk size. */ - protected static final int INITIAL_CHUNK_COUNT = (1 << (16 - CHUNK_SHIFT)); // 2^16 = 64k + protected static final int INITIAL_CHUNK_COUNT = (1 << (13 - CHUNK_SHIFT)); // 32 // // Data
--- a/src/java.xml/share/legal/xerces.md Thu May 23 22:14:23 2019 +0200 +++ b/src/java.xml/share/legal/xerces.md Thu May 30 19:51:24 2019 +0200 @@ -1,14 +1,14 @@ -## Apache Xerces v2.11.0 +## Apache Xerces v2.12.0 ### Apache Xerces Notice <pre> ========================================================================= - == NOTICE file corresponding to section 4(d) of the Apache License, == - == Version 2.0, in this case for the Apache Xerces Java distribution. == + == NOTICE file corresponding to section 4(d) of the Apache License, == + == Version 2.0, in this case for the Apache Xerces Java distribution. == ========================================================================= Apache Xerces Java - Copyright 1999-2010 The Apache Software Foundation + Copyright 1999-2018 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). Portions of this software were originally based on the following:
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.PhaseSuite; @@ -194,7 +195,16 @@ AOTDynamicTypeStore dynoStore = new AOTDynamicTypeStore(); AOTCompiledClass.setDynamicTypeStore(dynoStore); - AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, new HotSpotInvokeDynamicPlugin(dynoStore)); + // AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, new HotSpotInvokeDynamicPlugin(dynoStore)); + // Temporary workaround until JDK-8223533 is fixed. + // Disable invokedynamic support. + var indyPlugin = new HotSpotInvokeDynamicPlugin(dynoStore) { + @Override + public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) { + return false; + } + }; + AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, indyPlugin); SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection(); AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads); classes = compiler.compileClasses(classes);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Thu May 30 19:51:24 2019 +0200 @@ -355,7 +355,7 @@ private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules, ClassSymbol c) { // update the module for each compilation unit if (multiModuleMode) { - checkNoAllModulePath(); + boolean patchesAutomaticModules = false; for (JCCompilationUnit tree: trees) { if (tree.defs.isEmpty()) { tree.modle = syms.unnamedModule; @@ -375,6 +375,7 @@ ModuleSymbol msym = moduleFinder.findModule(name); tree.modle = msym; rootModules.add(msym); + patchesAutomaticModules |= (msym.flags_field & Flags.AUTOMATIC_MODULE) != 0; if (msplocn != null) { Name mspname = names.fromString(fileManager.inferModuleName(msplocn)); @@ -438,6 +439,9 @@ log.useSource(prev); } } + if (!patchesAutomaticModules) { + checkNoAllModulePath(); + } if (syms.unnamedModule.sourceLocation == null) { syms.unnamedModule.completer = getUnnamedModuleCompleter(); syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH; @@ -458,9 +462,11 @@ } if (defaultModule == syms.unnamedModule) { if (moduleOverride != null) { - checkNoAllModulePath(); defaultModule = moduleFinder.findModule(names.fromString(moduleOverride)); defaultModule.patchOutputLocation = StandardLocation.CLASS_OUTPUT; + if ((defaultModule.flags_field & Flags.AUTOMATIC_MODULE) == 0) { + checkNoAllModulePath(); + } } else { // Question: why not do findAllModules and initVisiblePackages here? // i.e. body of unnamedModuleCompleter
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Thu May 30 19:51:24 2019 +0200 @@ -686,11 +686,12 @@ static class ProcessorState { public Processor processor; public boolean contributed; - private ArrayList<Pattern> supportedAnnotationPatterns; - private ArrayList<String> supportedOptionNames; + private Set<String> supportedAnnotationStrings; // Used for warning generation + private Set<Pattern> supportedAnnotationPatterns; + private Set<String> supportedOptionNames; ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh, - boolean allowModules, ProcessingEnvironment env) { + boolean allowModules, ProcessingEnvironment env, boolean lint) { processor = p; contributed = false; @@ -700,18 +701,46 @@ checkSourceVersionCompatibility(source, log); - supportedAnnotationPatterns = new ArrayList<>(); - for (String importString : processor.getSupportedAnnotationTypes()) { - supportedAnnotationPatterns.add(importStringToPattern(allowModules, - importString, - processor, - log)); + + // Check for direct duplicates in the strings of + // supported annotation types. Do not check for + // duplicates that would result after stripping of + // module prefixes. + supportedAnnotationStrings = new LinkedHashSet<>(); + supportedAnnotationPatterns = new LinkedHashSet<>(); + for (String annotationPattern : processor.getSupportedAnnotationTypes()) { + boolean patternAdded = supportedAnnotationStrings.add(annotationPattern); + + supportedAnnotationPatterns. + add(importStringToPattern(allowModules, annotationPattern, + processor, log, lint)); + if (lint && !patternAdded) { + log.warning(Warnings.ProcDuplicateSupportedAnnotation(annotationPattern, + p.getClass().getName())); + } } - supportedOptionNames = new ArrayList<>(); + // If a processor supports "*", that matches + // everything and other entries are redundant. With + // more work, it could be checked that the supported + // annotation types were otherwise non-overlapping + // with each other in other cases, for example "foo.*" + // and "foo.bar.*". + if (lint && + supportedAnnotationPatterns.contains(MatchingUtils.validImportStringToPattern("*")) && + supportedAnnotationPatterns.size() > 1) { + log.warning(Warnings.ProcRedundantTypesWithWildcard(p.getClass().getName())); + } + + supportedOptionNames = new LinkedHashSet<>(); for (String optionName : processor.getSupportedOptions() ) { - if (checkOptionName(optionName, log)) - supportedOptionNames.add(optionName); + if (checkOptionName(optionName, log)) { + boolean optionAdded = supportedOptionNames.add(optionName); + if (lint && !optionAdded) { + log.warning(Warnings.ProcDuplicateOptionName(optionName, + p.getClass().getName())); + } + } } } catch (ClientCodeException e) { @@ -797,7 +826,8 @@ ProcessorState ps = new ProcessorState(psi.processorIterator.next(), log, source, dcfh, Feature.MODULES.allowedInSource(source), - JavacProcessingEnvironment.this); + JavacProcessingEnvironment.this, + lint); psi.procStateList.add(ps); return ps; } else @@ -1705,7 +1735,7 @@ * regex matching that string. If the string is not a valid * import-style string, return a regex that won't match anything. */ - private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log) { + private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log, boolean lint) { String module; String pkg; int slash = s.indexOf('/'); @@ -1716,15 +1746,26 @@ module = allowModules ? ".*/" : ""; pkg = s; } else { - module = Pattern.quote(s.substring(0, slash + 1)); + String moduleName = s.substring(0, slash); + if (!SourceVersion.isIdentifier(moduleName)) { + return warnAndNoMatches(s, p, log, lint); + } + module = Pattern.quote(moduleName + "/"); + // And warn if module is specified if modules aren't supported, conditional on -Xlint:proc? pkg = s.substring(slash + 1); } if (MatchingUtils.isValidImportString(pkg)) { return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg)); } else { + return warnAndNoMatches(s, p, log, lint); + } + } + + private static Pattern warnAndNoMatches(String s, Processor p, Log log, boolean lint) { + if (lint) { log.warning(Warnings.ProcMalformedSupportedString(s, p.getClass().getName())); - return noMatches; // won't match any valid identifier } + return noMatches; // won't match any valid identifier } /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Thu May 30 19:51:24 2019 +0200 @@ -1917,6 +1917,18 @@ compiler.warn.proc.processor.incompatible.source.version=\ Supported source version ''{0}'' from annotation processor ''{1}'' less than -source ''{2}'' +# 0: string, 1: string +compiler.warn.proc.duplicate.option.name=\ + Duplicate supported option ''{0}'' returned by annotation processor ''{1}'' + +# 0: string, 1: string +compiler.warn.proc.duplicate.supported.annotation=\ + Duplicate supported annotation type ''{0}'' returned by annotation processor ''{1}'' + +# 0: string +compiler.warn.proc.redundant.types.with.wildcard=\ + Annotation processor ''{0}'' redundantly supports both ''*'' and other annotation types + compiler.warn.proc.proc-only.requested.no.procs=\ Annotation processing without compilation requested but no processors were found. @@ -3298,7 +3310,8 @@ module name in {0} option not found: {1} compiler.err.addmods.all.module.path.invalid=\ - --add-modules ALL-MODULE-PATH can only be used when compiling the unnamed module + --add-modules ALL-MODULE-PATH can only be used when compiling the unnamed module or \ + when compiling in the context of an automatic module # 0: symbol compiler.err.add.exports.with.release=\
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.c Thu May 30 19:51:24 2019 +0200 @@ -38,7 +38,11 @@ #define amd64 1 #endif -#ifdef i386 +#if defined(i386) && !defined(i586) +#define i586 1 +#endif + +#ifdef i586 #include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h" #endif @@ -386,7 +390,7 @@ return (err == PS_OK)? array : 0; } -#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(ppc64le) || defined(aarch64) +#if defined(i586) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(ppc64le) || defined(aarch64) JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 (JNIEnv *env, jobject this_obj, jint lwp_id) { @@ -402,7 +406,7 @@ } #undef NPRGREG -#ifdef i386 +#ifdef i586 #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG #endif #ifdef amd64 @@ -425,7 +429,7 @@ #undef REG_INDEX -#ifdef i386 +#ifdef i586 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##reg regs[REG_INDEX(GS)] = (uintptr_t) gregs.xgs; @@ -444,7 +448,7 @@ regs[REG_INDEX(CS)] = (uintptr_t) gregs.xcs; regs[REG_INDEX(SS)] = (uintptr_t) gregs.xss; -#endif /* i386 */ +#endif /* i586 */ #ifdef amd64 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c Thu May 30 19:51:24 2019 +0200 @@ -961,7 +961,7 @@ if (is_debug()) { print_debug("integer regset\n"); -#ifdef i386 +#if defined(i586) || defined(i386) // print the regset print_debug("\teax = 0x%x\n", newthr->regs.r_eax); print_debug("\tebx = 0x%x\n", newthr->regs.r_ebx);
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java Thu May 30 19:51:24 2019 +0200 @@ -45,30 +45,38 @@ return false; } - private static boolean commonHelp() { + private static boolean commonHelp(String mode) { // --pid <pid> // --exe <exe> // --core <core> - System.out.println(" --exe\t<executable image name>"); - System.out.println(" --core\t<path to coredump>"); - System.out.println(" --pid\t<pid of process to attach>"); + System.out.println(" --pid <pid> \tTo attach to and operate on the given live process."); + System.out.println(" --core <corefile>\tTo operate on the given core file."); + System.out.println(" --exe <executable for corefile>"); + System.out.println(); + System.out.println(" The --core and --exe options must be set together to give the core"); + System.out.println(" file, and associated executable, to operate on. Otherwise the --pid"); + System.out.println(" option can be set to operate on a live process."); + System.out.println(" The arguments for --exe and --core can use absolute or relative paths."); + System.out.println(); + System.out.println(" Examples: jhsdb " + mode + " --pid 1234"); + System.out.println(" or jhsdb " + mode + " --core ./core.1234 --exe ./myexe"); return false; } private static boolean debugdHelp() { // [options] <pid> [server-id] // [options] <executable> <core> [server-id] - System.out.println(" --serverid\t<unique id for this debug server>"); - return commonHelp(); + System.out.println(" --serverid <id> \tA unique identifier for this debug server."); + return commonHelp("debugd"); } private static boolean jinfoHelp() { // --flags -> -flags // --sysprops -> -sysprops - System.out.println(" --flags\tto print VM flags"); - System.out.println(" --sysprops\tto print Java System properties"); - System.out.println(" <no option>\tto print both of the above"); - return commonHelp(); + System.out.println(" --flags \tTo print VM flags."); + System.out.println(" --sysprops \tTo print Java System properties."); + System.out.println(" <no option> \tTo print both of the above."); + return commonHelp("jinfo"); } private static boolean jmapHelp() { @@ -78,27 +86,27 @@ // --clstats -> -clstats // --finalizerinfo -> -finalizerinfo - System.out.println(" <no option>\tto print same info as Solaris pmap"); - System.out.println(" --heap\tto print java heap summary"); - System.out.println(" --binaryheap\tto dump java heap in hprof binary format"); - System.out.println(" --dumpfile\tname of the dump file"); - System.out.println(" --histo\tto print histogram of java object heap"); - System.out.println(" --clstats\tto print class loader statistics"); - System.out.println(" --finalizerinfo\tto print information on objects awaiting finalization"); - return commonHelp(); + System.out.println(" <no option> \tTo print same info as Solaris pmap."); + System.out.println(" --heap \tTo print java heap summary."); + System.out.println(" --binaryheap \tTo dump java heap in hprof binary format."); + System.out.println(" --dumpfile <name>\tThe name of the dump file."); + System.out.println(" --histo \tTo print histogram of java object heap."); + System.out.println(" --clstats \tTo print class loader statistics."); + System.out.println(" --finalizerinfo \tTo print information on objects awaiting finalization."); + return commonHelp("jmap"); } private static boolean jstackHelp() { // --locks -> -l // --mixed -> -m - System.out.println(" --locks\tto print java.util.concurrent locks"); - System.out.println(" --mixed\tto print both java and native frames (mixed mode)"); - return commonHelp(); + System.out.println(" --locks \tTo print java.util.concurrent locks."); + System.out.println(" --mixed \tTo print both Java and native frames (mixed mode)."); + return commonHelp("jstack"); } private static boolean jsnapHelp() { - System.out.println(" --all\tto print all performance counters"); - return commonHelp(); + System.out.println(" --all \tTo print all performance counters."); + return commonHelp("jsnap"); } private static boolean toolHelp(String toolName) { @@ -117,8 +125,11 @@ if (toolName.equals("debugd")) { return debugdHelp(); } - if (toolName.equals("hsdb") || toolName.equals("clhsdb")) { - return commonHelp(); + if (toolName.equals("hsdb")) { + return commonHelp("hsdb"); + } + if (toolName.equals("clhsdb")) { + return commonHelp("clhsdb"); } return launcherHelp(); }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java Thu May 23 22:14:23 2019 +0200 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java Thu May 30 19:51:24 2019 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.SimpleElementVisitor9; @@ -564,7 +565,6 @@ boolean allowInheritedMethods(ExecutableElement inheritedMethod, Map<ExecutableElement, List<ExecutableElement>> inheritedOverriddenTable, LocalMemberTable lmt) { - if (!isInherited(inheritedMethod)) return false; @@ -598,7 +598,8 @@ // Check the local methods in this type. List<Element> lMethods = lmt.getMembers(inheritedMethod, Kind.METHODS); - for (Element lMethod : lMethods) { + for (Element le : lMethods) { + ExecutableElement lMethod = (ExecutableElement) le; // Ignore private methods or those methods marked with // a "hidden" tag. if (utils.isPrivate(lMethod)) @@ -611,18 +612,26 @@ } // Check for overriding methods. - if (elementUtils.overrides((ExecutableElement)lMethod, inheritedMethod, + if (elementUtils.overrides(lMethod, inheritedMethod, utils.getEnclosingTypeElement(lMethod))) { // Disallow package-private super methods to leak in TypeElement encl = utils.getEnclosingTypeElement(inheritedMethod); if (isUndocumentedEnclosure(encl)) { - overriddenMethodTable.computeIfAbsent((ExecutableElement)lMethod, + overriddenMethodTable.computeIfAbsent(lMethod, l -> new OverridingMethodInfo(inheritedMethod, false)); return false; } - boolean simpleOverride = utils.isSimpleOverride((ExecutableElement)lMethod); - overriddenMethodTable.computeIfAbsent((ExecutableElement)lMethod, + + TypeMirror inheritedMethodReturn = inheritedMethod.getReturnType(); + TypeMirror lMethodReturn = lMethod.getReturnType(); + boolean covariantReturn = + lMethodReturn.getKind() == TypeKind.DECLARED + && inheritedMethodReturn.getKind() == TypeKind.DECLARED + && !utils.typeUtils.isSameType(lMethodReturn, inheritedMethodReturn) + && utils.typeUtils.isSubtype(lMethodReturn, inheritedMethodReturn); + boolean simpleOverride = covariantReturn ? false : utils.isSimpleOverride(lMethod); + overriddenMethodTable.computeIfAbsent(lMethod, l -> new OverridingMethodInfo(inheritedMethod, simpleOverride)); return simpleOverride; } @@ -987,5 +996,10 @@ this.overrider = overrider; this.simpleOverride = simpleOverride; } + + @Override + public String toString() { + return "OverridingMethodInfo[" + overrider + ",simple:" + simpleOverride + "]"; + } } }
--- a/test/fmw/gtest/CHANGES Thu May 23 22:14:23 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -Changes for 1.7.0: - -* New feature: death tests are supported on OpenBSD and in iOS - simulator now. -* New feature: Google Test now implements a protocol to allow - a test runner to detect that a test program has exited - prematurely and report it as a failure (before it would be - falsely reported as a success if the exit code is 0). -* New feature: Test::RecordProperty() can now be used outside of the - lifespan of a test method, in which case it will be attributed to - the current test case or the test program in the XML report. -* New feature (potentially breaking): --gtest_list_tests now prints - the type parameters and value parameters for each test. -* Improvement: char pointers and char arrays are now escaped properly - in failure messages. -* Improvement: failure summary in XML reports now includes file and - line information. -* Improvement: the <testsuites> XML element now has a timestamp attribute. -* Improvement: When --gtest_filter is specified, XML report now doesn't - contain information about tests that are filtered out. -* Fixed the bug where long --gtest_filter flag values are truncated in - death tests. -* Potentially breaking change: RUN_ALL_TESTS() is now implemented as a - function instead of a macro in order to work better with Clang. -* Compatibility fixes with C++ 11 and various platforms. -* Bug/warning fixes. - -Changes for 1.6.0: - -* New feature: ADD_FAILURE_AT() for reporting a test failure at the - given source location -- useful for writing testing utilities. -* New feature: the universal value printer is moved from Google Mock - to Google Test. -* New feature: type parameters and value parameters are reported in - the XML report now. -* A gtest_disable_pthreads CMake option. -* Colored output works in GNU Screen sessions now. -* Parameters of value-parameterized tests are now printed in the - textual output. -* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are - now correctly reported. -* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to - ostream. -* More complete handling of exceptions. -* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter - name is already used by another library. -* --gtest_catch_exceptions is now true by default, allowing a test - program to continue after an exception is thrown. -* Value-parameterized test fixtures can now derive from Test and - WithParamInterface<T> separately, easing conversion of legacy tests. -* Death test messages are clearly marked to make them more - distinguishable from other messages. -* Compatibility fixes for Android, Google Native Client, MinGW, HP UX, - PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear), - IBM XL C++ (Visual Age C++), and C++0x. -* Bug fixes and implementation clean-ups. -* Potentially incompatible changes: disables the harmful 'make install' - command in autotools. - -Changes for 1.5.0: - - * New feature: assertions can be safely called in multiple threads - where the pthreads library is available. - * New feature: predicates used inside EXPECT_TRUE() and friends - can now generate custom failure messages. - * New feature: Google Test can now be compiled as a DLL.