diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 7650eaf463c..7df77702890 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -868,9 +868,10 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, // load first parts of strings and finish initialization while loading { if (str1_isL == str2_isL) { // LL or UU + // check if str1 and str2 is same pointer + beq(str1, str2, DONE); // load 8 bytes once to compare ld(tmp1, Address(str1)); - beq(str1, str2, DONE); ld(tmp2, Address(str2)); mv(t0, STUB_THRESHOLD); bge(cnt2, t0, STUB); @@ -913,9 +914,8 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, addi(cnt1, cnt1, 8); } addi(cnt2, cnt2, isUL ? 4 : 8); + bne(tmp1, tmp2, DIFFERENCE); bgez(cnt2, TAIL); - xorr(tmp3, tmp1, tmp2); - bnez(tmp3, DIFFERENCE); // main loop bind(NEXT_WORD); @@ -944,38 +944,30 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, addi(cnt1, cnt1, 8); addi(cnt2, cnt2, 4); } - bgez(cnt2, TAIL); - - xorr(tmp3, tmp1, tmp2); - beqz(tmp3, NEXT_WORD); - j(DIFFERENCE); + bne(tmp1, tmp2, DIFFERENCE); + bltz(cnt2, NEXT_WORD); bind(TAIL); - xorr(tmp3, tmp1, tmp2); - bnez(tmp3, DIFFERENCE); - // Last longword. In the case where length == 4 we compare the - // same longword twice, but that's still faster than another - // conditional branch. if (str1_isL == str2_isL) { // LL or UU - ld(tmp1, Address(str1)); - ld(tmp2, Address(str2)); + load_long_misaligned(tmp1, Address(str1), tmp3, isLL ? 1 : 2); + load_long_misaligned(tmp2, Address(str2), tmp3, isLL ? 1 : 2); } else if (isLU) { // LU case - lwu(tmp1, Address(str1)); - ld(tmp2, Address(str2)); + load_int_misaligned(tmp1, Address(str1), tmp3, false); + load_long_misaligned(tmp2, Address(str2), tmp3, 2); inflate_lo32(tmp3, tmp1); mv(tmp1, tmp3); } else { // UL case - lwu(tmp2, Address(str2)); - ld(tmp1, Address(str1)); + load_int_misaligned(tmp2, Address(str2), tmp3, false); + load_long_misaligned(tmp1, Address(str1), tmp3, 2); inflate_lo32(tmp3, tmp2); mv(tmp2, tmp3); } bind(TAIL_CHECK); - xorr(tmp3, tmp1, tmp2); - beqz(tmp3, DONE); + beq(tmp1, tmp2, DONE); // Find the first different characters in the longwords and // compute their difference. bind(DIFFERENCE); + xorr(tmp3, tmp1, tmp2); ctzc_bit(result, tmp3, isLL); // count zero from lsb to msb srl(tmp1, tmp1, result); srl(tmp2, tmp2, result); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index e0a216ab4a7..68960118076 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3967,18 +3967,17 @@ void MacroAssembler::ctzc_bit(Register Rd, Register Rs, bool isLL, Register tmp1 void MacroAssembler::inflate_lo32(Register Rd, Register Rs, Register tmp1, Register tmp2) { assert_different_registers(Rd, Rs, tmp1, tmp2); - mv(tmp1, 0xFF); - mv(Rd, zr); - for (int i = 0; i <= 3; i++) { + mv(tmp1, 0xFF000000); // first byte mask at lower word + andr(Rd, Rs, tmp1); + for (int i = 0; i < 2; i++) { + slli(Rd, Rd, wordSize); + srli(tmp1, tmp1, wordSize); andr(tmp2, Rs, tmp1); - if (i) { - slli(tmp2, tmp2, i * 8); - } orr(Rd, Rd, tmp2); - if (i != 3) { - slli(tmp1, tmp1, 8); - } } + slli(Rd, Rd, wordSize); + andi(tmp2, Rs, 0xFF); // last byte mask at lower word + orr(Rd, Rd, tmp2); } // This instruction reads adjacent 4 bytes from the upper half of source register, @@ -3987,17 +3986,8 @@ void MacroAssembler::inflate_lo32(Register Rd, Register Rs, Register tmp1, Regis // Rd: 00A700A600A500A4 void MacroAssembler::inflate_hi32(Register Rd, Register Rs, Register tmp1, Register tmp2) { assert_different_registers(Rd, Rs, tmp1, tmp2); - - mv(tmp1, 0xFF00000000); - mv(Rd, zr); - for (int i = 0; i <= 3; i++) { - andr(tmp2, Rs, tmp1); - orr(Rd, Rd, tmp2); - srli(Rd, Rd, 8); - if (i != 3) { - slli(tmp1, tmp1, 8); - } - } + srli(Rs, Rs, 32); // only upper 32 bits are needed + inflate_lo32(Rd, Rs, tmp1, tmp2); } // The size of the blocks erased by the zero_blocks stub. We must diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 98d94ccd15b..304e0a9c222 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2275,24 +2275,21 @@ class StubGenerator: public StubCodeGenerator { } // code for comparing 8 characters of strings with Latin1 and Utf16 encoding - void compare_string_8_x_LU(Register tmpL, Register tmpU, Label &DIFF1, - Label &DIFF2) { - const Register strU = x12, curU = x7, strL = x29, tmp = x30; - __ ld(tmpL, Address(strL)); - __ addi(strL, strL, 8); + void compare_string_8_x_LU(Register tmpL, Register tmpU, Register strL, Register strU, Label& DIFF) { + const Register tmp = x30, tmpLval = x12; + __ ld(tmpLval, Address(strL)); + __ addi(strL, strL, wordSize); __ ld(tmpU, Address(strU)); - __ addi(strU, strU, 8); - __ inflate_lo32(tmp, tmpL); - __ mv(t0, tmp); - __ xorr(tmp, curU, t0); - __ bnez(tmp, DIFF2); - - __ ld(curU, Address(strU)); - __ addi(strU, strU, 8); - __ inflate_hi32(tmp, tmpL); - __ mv(t0, tmp); - __ xorr(tmp, tmpU, t0); - __ bnez(tmp, DIFF1); + __ addi(strU, strU, wordSize); + __ inflate_lo32(tmpL, tmpLval); + __ xorr(tmp, tmpU, tmpL); + __ bnez(tmp, DIFF); + + __ ld(tmpU, Address(strU)); + __ addi(strU, strU, wordSize); + __ inflate_hi32(tmpL, tmpLval); + __ xorr(tmp, tmpU, tmpL); + __ bnez(tmp, DIFF); } // x10 = result @@ -2307,11 +2304,9 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", isLU ? "compare_long_string_different_encoding LU" : "compare_long_string_different_encoding UL"); address entry = __ pc(); - Label SMALL_LOOP, TAIL, TAIL_LOAD_16, LOAD_LAST, DIFF1, DIFF2, - DONE, CALCULATE_DIFFERENCE; - const Register result = x10, str1 = x11, cnt1 = x12, str2 = x13, cnt2 = x14, - tmp1 = x28, tmp2 = x29, tmp3 = x30, tmp4 = x7, tmp5 = x31; - RegSet spilled_regs = RegSet::of(tmp4, tmp5); + Label SMALL_LOOP, TAIL, LOAD_LAST, DONE, CALCULATE_DIFFERENCE; + const Register result = x10, str1 = x11, str2 = x13, cnt2 = x14, + tmp1 = x28, tmp2 = x29, tmp3 = x30, tmp4 = x12; // cnt2 == amount of characters left to compare // Check already loaded first 4 symbols @@ -2319,77 +2314,81 @@ class StubGenerator: public StubCodeGenerator { __ mv(isLU ? tmp1 : tmp2, tmp3); __ addi(str1, str1, isLU ? wordSize / 2 : wordSize); __ addi(str2, str2, isLU ? wordSize : wordSize / 2); - __ sub(cnt2, cnt2, 8); // Already loaded 4 symbols. Last 4 is special case. - __ push_reg(spilled_regs, sp); + __ sub(cnt2, cnt2, wordSize / 2); // Already loaded 4 symbols - if (isLU) { - __ add(str1, str1, cnt2); - __ shadd(str2, cnt2, str2, t0, 1); - } else { - __ shadd(str1, cnt2, str1, t0, 1); - __ add(str2, str2, cnt2); - } __ xorr(tmp3, tmp1, tmp2); - __ mv(tmp5, tmp2); __ bnez(tmp3, CALCULATE_DIFFERENCE); Register strU = isLU ? str2 : str1, strL = isLU ? str1 : str2, - tmpU = isLU ? tmp5 : tmp1, // where to keep U for comparison - tmpL = isLU ? tmp1 : tmp5; // where to keep L for comparison + tmpU = isLU ? tmp2 : tmp1, // where to keep U for comparison + tmpL = isLU ? tmp1 : tmp2; // where to keep L for comparison - __ sub(tmp2, strL, cnt2); // strL pointer to load from - __ slli(t0, cnt2, 1); - __ sub(cnt1, strU, t0); // strU pointer to load from + // make sure main loop is 8 byte-aligned, we should load another 4 bytes from strL + // cnt2 is >= 68 here, no need to check it for >= 0 + __ lwu(tmpL, Address(strL)); + __ addi(strL, strL, wordSize / 2); + __ ld(tmpU, Address(strU)); + __ addi(strU, strU, wordSize); + __ inflate_lo32(tmp3, tmpL); + __ mv(tmpL, tmp3); + __ xorr(tmp3, tmpU, tmpL); + __ bnez(tmp3, CALCULATE_DIFFERENCE); + __ addi(cnt2, cnt2, -wordSize / 2); - __ ld(tmp4, Address(cnt1)); - __ addi(cnt1, cnt1, 8); - __ beqz(cnt2, LOAD_LAST); // no characters left except last load - __ sub(cnt2, cnt2, 16); + // we are now 8-bytes aligned on strL + __ sub(cnt2, cnt2, wordSize * 2); __ bltz(cnt2, TAIL); __ bind(SMALL_LOOP); // smaller loop - __ sub(cnt2, cnt2, 16); - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); + __ sub(cnt2, cnt2, wordSize * 2); + compare_string_8_x_LU(tmpL, tmpU, strL, strU, CALCULATE_DIFFERENCE); + compare_string_8_x_LU(tmpL, tmpU, strL, strU, CALCULATE_DIFFERENCE); __ bgez(cnt2, SMALL_LOOP); - __ addi(t0, cnt2, 16); - __ beqz(t0, LOAD_LAST); - __ bind(TAIL); // 1..15 characters left until last load (last 4 characters) - // Address of 8 bytes before last 4 characters in UTF-16 string - __ shadd(cnt1, cnt2, cnt1, t0, 1); - // Address of 16 bytes before last 4 characters in Latin1 string - __ add(tmp2, tmp2, cnt2); - __ ld(tmp4, Address(cnt1, -8)); - // last 16 characters before last load - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); - compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); - __ j(LOAD_LAST); - __ bind(DIFF2); - __ mv(tmpU, tmp4); - __ bind(DIFF1); - __ mv(tmpL, t0); - __ j(CALCULATE_DIFFERENCE); - __ bind(LOAD_LAST); - // Last 4 UTF-16 characters are already pre-loaded into tmp4 by compare_string_8_x_LU. - // No need to load it again - __ mv(tmpU, tmp4); - __ ld(tmpL, Address(strL)); + __ addi(t0, cnt2, wordSize * 2); + __ beqz(t0, DONE); + __ bind(TAIL); // 1..15 characters left + // Aligned access. Load bytes in portions - 4, 2, 1. + + __ addi(t0, cnt2, wordSize); + __ addi(cnt2, cnt2, wordSize * 2); // amount of characters left to process + __ bltz(t0, LOAD_LAST); + // remaining characters are greater than or equals to 8, we can do one compare_string_8_x_LU + compare_string_8_x_LU(tmpL, tmpU, strL, strU, CALCULATE_DIFFERENCE); + __ addi(cnt2, cnt2, -wordSize); + __ beqz(cnt2, DONE); // no character left + __ bind(LOAD_LAST); // cnt2 = 1..7 characters left + + __ addi(cnt2, cnt2, -wordSize); // cnt2 is now an offset in strL which points to last 8 bytes + __ slli(t0, cnt2, 1); // t0 is now an offset in strU which points to last 16 bytes + __ add(strL, strL, cnt2); // Address of last 8 bytes in Latin1 string + __ add(strU, strU, t0); // Address of last 16 bytes in UTF-16 string + __ load_int_misaligned(tmpL, Address(strL), t0, false); + __ load_long_misaligned(tmpU, Address(strU), t0, 2); __ inflate_lo32(tmp3, tmpL); __ mv(tmpL, tmp3); __ xorr(tmp3, tmpU, tmpL); - __ beqz(tmp3, DONE); + __ bnez(tmp3, CALCULATE_DIFFERENCE); + + __ addi(strL, strL, wordSize / 2); // Address of last 4 bytes in Latin1 string + __ addi(strU, strU, wordSize); // Address of last 8 bytes in UTF-16 string + __ load_int_misaligned(tmpL, Address(strL), t0, false); + __ load_long_misaligned(tmpU, Address(strU), t0, 2); + __ inflate_lo32(tmp3, tmpL); + __ mv(tmpL, tmp3); + __ xorr(tmp3, tmpU, tmpL); + __ bnez(tmp3, CALCULATE_DIFFERENCE); + __ j(DONE); // no character left // Find the first different characters in the longwords and // compute their difference. __ bind(CALCULATE_DIFFERENCE); __ ctzc_bit(tmp4, tmp3); __ srl(tmp1, tmp1, tmp4); - __ srl(tmp5, tmp5, tmp4); + __ srl(tmp2, tmp2, tmp4); __ andi(tmp1, tmp1, 0xFFFF); - __ andi(tmp5, tmp5, 0xFFFF); - __ sub(result, tmp1, tmp5); + __ andi(tmp2, tmp2, 0xFFFF); + __ sub(result, tmp1, tmp2); __ bind(DONE); - __ pop_reg(spilled_regs, sp); __ ret(); return entry; } @@ -2502,9 +2501,9 @@ class StubGenerator: public StubCodeGenerator { __ xorr(tmp4, tmp1, tmp2); __ bnez(tmp4, DIFF); __ add(str1, str1, cnt2); - __ ld(tmp5, Address(str1)); + __ load_long_misaligned(tmp5, Address(str1), tmp3, isLL ? 1 : 2); __ add(str2, str2, cnt2); - __ ld(cnt1, Address(str2)); + __ load_long_misaligned(cnt1, Address(str2), tmp3, isLL ? 1 : 2); __ xorr(tmp4, tmp5, cnt1); __ beqz(tmp4, LENGTH_DIFF); // Find the first different characters in the longwords and diff --git a/src/hotspot/os/linux/trimCHeapDCmd.cpp b/src/hotspot/os/linux/trimCHeapDCmd.cpp index 33dd6f3a5bd..26c066ffe5b 100644 --- a/src/hotspot/os/linux/trimCHeapDCmd.cpp +++ b/src/hotspot/os/linux/trimCHeapDCmd.cpp @@ -24,6 +24,7 @@ */ #include "precompiled.hpp" +#include "logging/log.hpp" #include "runtime/os.inline.hpp" #include "trimCHeapDCmd.hpp" #include "utilities/debug.hpp" @@ -42,6 +43,9 @@ void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { const char sign = sc.after < sc.before ? '-' : '+'; _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")", PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta)); + // Also log if native trim log is active + log_info(trimnative)("Manual Trim: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")", + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta)); } else { _output->print_cr("(no details available)."); } diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index 22299b4051b..ec06cbb1b41 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -32,6 +32,7 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueType.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/compilerDirectives.hpp" #include "interpreter/linkResolver.hpp" #include "jfr/support/jfrIntrinsics.hpp" #include "memory/allocation.hpp" diff --git a/src/hotspot/share/c1/c1_Compiler.hpp b/src/hotspot/share/c1/c1_Compiler.hpp index 9ff313f68ac..8f2afa85dba 100644 --- a/src/hotspot/share/c1/c1_Compiler.hpp +++ b/src/hotspot/share/c1/c1_Compiler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, 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 @@ -26,7 +26,8 @@ #define SHARE_C1_C1_COMPILER_HPP #include "compiler/abstractCompiler.hpp" -#include "compiler/compilerDirectives.hpp" + +class DirectiveSet; // There is one instance of the Compiler per CompilerThread. diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index 578b171a552..9735edcdcd0 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -29,6 +29,7 @@ #include "jvm_constants.h" #include "jvm_io.h" #include "runtime/vm_version.hpp" +#include "utilities/tribool.hpp" #include "utilities/xmlstream.hpp" // These are flag-matching functions: diff --git a/src/hotspot/share/classfile/vmSymbols.cpp b/src/hotspot/share/classfile/vmSymbols.cpp index 36cfca83dd8..05cd4767e9a 100644 --- a/src/hotspot/share/classfile/vmSymbols.cpp +++ b/src/hotspot/share/classfile/vmSymbols.cpp @@ -34,7 +34,6 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" -#include "utilities/tribool.hpp" #include "utilities/xmlstream.hpp" diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 2ea72a1fcbd..dd95025b968 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -310,9 +310,20 @@ void CodeCache::initialize_heaps() { FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled_size); FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled_size); + const size_t ps = page_size(false, 8); + // Print warning if using large pages but not able to use the size given + if (UseLargePages) { + const size_t lg_ps = page_size(false, 1); + if (ps < lg_ps) { + log_warning(codecache)("Code cache size too small for " PROPERFMT " pages. " + "Reverting to smaller page size (" PROPERFMT ").", + PROPERFMTARGS(lg_ps), PROPERFMTARGS(ps)); + } + } + // If large page support is enabled, align code heaps according to large // page size to make sure that code cache is covered by large pages. - const size_t alignment = MAX2(page_size(false, 8), os::vm_allocation_granularity()); + const size_t alignment = MAX2(ps, os::vm_allocation_granularity()); non_nmethod_size = align_up(non_nmethod_size, alignment); profiled_size = align_down(profiled_size, alignment); non_profiled_size = align_down(non_profiled_size, alignment); @@ -324,7 +335,7 @@ void CodeCache::initialize_heaps() { // Non-nmethods // Profiled nmethods // ---------- low ------------ - ReservedCodeSpace rs = reserve_heap_memory(cache_size); + ReservedCodeSpace rs = reserve_heap_memory(cache_size, ps); ReservedSpace profiled_space = rs.first_part(profiled_size); ReservedSpace rest = rs.last_part(profiled_size); ReservedSpace non_method_space = rest.first_part(non_nmethod_size); @@ -354,9 +365,8 @@ size_t CodeCache::page_size(bool aligned, size_t min_pages) { } } -ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) { +ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size, size_t rs_ps) { // Align and reserve space for code cache - const size_t rs_ps = page_size(); const size_t rs_align = MAX2(rs_ps, os::vm_allocation_granularity()); const size_t rs_size = align_up(size, rs_align); ReservedCodeSpace rs(rs_size, rs_align, rs_ps); @@ -1194,7 +1204,7 @@ void CodeCache::initialize() { FLAG_SET_ERGO(NonNMethodCodeHeapSize, (uintx)os::vm_page_size()); FLAG_SET_ERGO(ProfiledCodeHeapSize, 0); FLAG_SET_ERGO(NonProfiledCodeHeapSize, 0); - ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize); + ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize, page_size(false, 8)); // Register CodeHeaps with LSan as we sometimes embed pointers to malloc memory. LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size()); add_heap(rs, "CodeCache", CodeBlobType::All); diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 6fb3a6bd981..5645d5067f6 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -121,7 +121,7 @@ class CodeCache : AllStatic { static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap static const char* get_code_heap_flag_name(CodeBlobType code_blob_type); - static ReservedCodeSpace reserve_heap_memory(size_t size); // Reserves one continuous chunk of memory for the CodeHeaps + static ReservedCodeSpace reserve_heap_memory(size_t size, size_t rs_ps); // Reserves one continuous chunk of memory for the CodeHeaps // Iteration static CodeBlob* first_blob(CodeHeap* heap); // Returns the first CodeBlob on the given CodeHeap diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index 9a1820c3017..8289239559c 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -127,8 +127,7 @@ GrowableArray* ArrayKlass::compute_secondary_supers(int num_extra_slots, objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) { check_array_allocation_length(length, arrayOopDesc::max_array_length(T_ARRAY), CHECK_NULL); size_t size = objArrayOopDesc::object_size(length); - Klass* k = array_klass(n+dimension(), CHECK_NULL); - ArrayKlass* ak = ArrayKlass::cast(k); + ArrayKlass* ak = array_klass(n + dimension(), CHECK_NULL); objArrayOop o = (objArrayOop)Universe::heap()->array_allocate(ak, size, length, /* do_zero */ true, CHECK_NULL); // initialization to null not necessary, area already cleared @@ -160,7 +159,7 @@ void ArrayKlass::metaspace_pointers_do(MetaspaceClosure* it) { void ArrayKlass::remove_unshareable_info() { Klass::remove_unshareable_info(); if (_higher_dimension != nullptr) { - ArrayKlass *ak = ArrayKlass::cast(higher_dimension()); + ArrayKlass *ak = higher_dimension(); ak->remove_unshareable_info(); } } @@ -168,7 +167,7 @@ void ArrayKlass::remove_unshareable_info() { void ArrayKlass::remove_java_mirror() { Klass::remove_java_mirror(); if (_higher_dimension != nullptr) { - ArrayKlass *ak = ArrayKlass::cast(higher_dimension()); + ArrayKlass *ak = higher_dimension(); ak->remove_java_mirror(); } } @@ -179,7 +178,7 @@ void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle p // Klass recreates the component mirror also if (_higher_dimension != nullptr) { - ArrayKlass *ak = ArrayKlass::cast(higher_dimension()); + ArrayKlass *ak = higher_dimension(); ak->restore_unshareable_info(loader_data, protection_domain, CHECK); } } @@ -188,7 +187,7 @@ void ArrayKlass::cds_print_value_on(outputStream* st) const { assert(is_klass(), "must be klass"); st->print(" - array: %s", internal_name()); if (_higher_dimension != nullptr) { - ArrayKlass* ak = ArrayKlass::cast(higher_dimension()); + ArrayKlass* ak = higher_dimension(); st->cr(); ak->cds_print_value_on(st); } diff --git a/src/hotspot/share/oops/arrayKlass.hpp b/src/hotspot/share/oops/arrayKlass.hpp index bf879202399..5461f1cb2eb 100644 --- a/src/hotspot/share/oops/arrayKlass.hpp +++ b/src/hotspot/share/oops/arrayKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, 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 @@ class fieldDescriptor; class klassVtable; +class ObjArrayKlass; // ArrayKlass is the abstract baseclass for all array classes @@ -38,8 +39,8 @@ class ArrayKlass: public Klass { // If you add a new field that points to any metaspace object, you // must add this field to ArrayKlass::metaspace_pointers_do(). int _dimension; // This is n'th-dimensional array. - Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present). - Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present). + ObjArrayKlass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present). + ArrayKlass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present). protected: // Constructors @@ -56,13 +57,13 @@ class ArrayKlass: public Klass { int dimension() const { return _dimension; } void set_dimension(int dimension) { _dimension = dimension; } - Klass* higher_dimension() const { return _higher_dimension; } - inline Klass* higher_dimension_acquire() const; // load with acquire semantics - void set_higher_dimension(Klass* k) { _higher_dimension = k; } - inline void release_set_higher_dimension(Klass* k); // store with release semantics + ObjArrayKlass* higher_dimension() const { return _higher_dimension; } + inline ObjArrayKlass* higher_dimension_acquire() const; // load with acquire semantics + void set_higher_dimension(ObjArrayKlass* k) { _higher_dimension = k; } + inline void release_set_higher_dimension(ObjArrayKlass* k); // store with release semantics - Klass* lower_dimension() const { return _lower_dimension; } - void set_lower_dimension(Klass* k) { _lower_dimension = k; } + ArrayKlass* lower_dimension() const { return _lower_dimension; } + void set_lower_dimension(ArrayKlass* k) { _lower_dimension = k; } // offset of first element, including any padding for the sake of alignment int array_header_in_bytes() const { return layout_helper_header_size(layout_helper()); } diff --git a/src/hotspot/share/oops/arrayKlass.inline.hpp b/src/hotspot/share/oops/arrayKlass.inline.hpp index d9e1b80718a..21794f82089 100644 --- a/src/hotspot/share/oops/arrayKlass.inline.hpp +++ b/src/hotspot/share/oops/arrayKlass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, 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,11 +29,11 @@ #include "runtime/atomic.hpp" -inline Klass* ArrayKlass::higher_dimension_acquire() const { +inline ObjArrayKlass* ArrayKlass::higher_dimension_acquire() const { return Atomic::load_acquire(&_higher_dimension); } -inline void ArrayKlass::release_set_higher_dimension(Klass* k) { +inline void ArrayKlass::release_set_higher_dimension(ObjArrayKlass* k) { Atomic::release_store(&_higher_dimension, k); } diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 8fd4eaefb12..a1c7eae402a 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1422,7 +1422,7 @@ bool InstanceKlass::is_same_or_direct_interface(Klass *k) const { objArrayOop InstanceKlass::allocate_objArray(int n, int length, TRAPS) { check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL); size_t size = objArrayOopDesc::object_size(length); - Klass* ak = array_klass(n, CHECK_NULL); + ArrayKlass* ak = array_klass(n, CHECK_NULL); objArrayOop o = (objArrayOop)Universe::heap()->array_allocate(ak, size, length, /* do_zero */ true, CHECK_NULL); return o; @@ -1486,7 +1486,7 @@ void InstanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) { } } -Klass* InstanceKlass::array_klass(int n, TRAPS) { +ArrayKlass* InstanceKlass::array_klass(int n, TRAPS) { // Need load-acquire for lock-free read if (array_klasses_acquire() == nullptr) { ResourceMark rm(THREAD); @@ -1508,7 +1508,7 @@ Klass* InstanceKlass::array_klass(int n, TRAPS) { return oak->array_klass(n, THREAD); } -Klass* InstanceKlass::array_klass_or_null(int n) { +ArrayKlass* InstanceKlass::array_klass_or_null(int n) { // Need load-acquire for lock-free read ObjArrayKlass* oak = array_klasses_acquire(); if (oak == nullptr) { @@ -1518,11 +1518,11 @@ Klass* InstanceKlass::array_klass_or_null(int n) { } } -Klass* InstanceKlass::array_klass(TRAPS) { +ArrayKlass* InstanceKlass::array_klass(TRAPS) { return array_klass(1, THREAD); } -Klass* InstanceKlass::array_klass_or_null() { +ArrayKlass* InstanceKlass::array_klass_or_null() { return array_klass_or_null(1); } diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 57edadde370..41313819573 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -1075,12 +1075,12 @@ class InstanceKlass: public Klass { // Lock during initialization public: // Returns the array class for the n'th dimension - virtual Klass* array_klass(int n, TRAPS); - virtual Klass* array_klass_or_null(int n); + virtual ArrayKlass* array_klass(int n, TRAPS); + virtual ArrayKlass* array_klass_or_null(int n); // Returns the array class with this class as element type - virtual Klass* array_klass(TRAPS); - virtual Klass* array_klass_or_null(); + virtual ArrayKlass* array_klass(TRAPS); + virtual ArrayKlass* array_klass_or_null(); static void clean_initialization_error_table(); diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 8469b9118f0..9d15894a490 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -539,14 +539,14 @@ class Klass : public Metadata { } // array class with specific rank - virtual Klass* array_klass(int rank, TRAPS) = 0; + virtual ArrayKlass* array_klass(int rank, TRAPS) = 0; // array class with this klass as element type - virtual Klass* array_klass(TRAPS) = 0; + virtual ArrayKlass* array_klass(TRAPS) = 0; // These will return null instead of allocating on the heap: - virtual Klass* array_klass_or_null(int rank) = 0; - virtual Klass* array_klass_or_null() = 0; + virtual ArrayKlass* array_klass_or_null(int rank) = 0; + virtual ArrayKlass* array_klass_or_null() = 0; virtual oop protection_domain() const = 0; diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index a0e3661e555..6cc6b5dce19 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -169,17 +169,14 @@ objArrayOop ObjArrayKlass::allocate(int length, TRAPS) { oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) { int length = *sizes; - // Call to lower_dimension uses this pointer, so most be called before a - // possible GC - Klass* ld_klass = lower_dimension(); + ArrayKlass* ld_klass = lower_dimension(); // If length < 0 allocate will throw an exception. objArrayOop array = allocate(length, CHECK_NULL); objArrayHandle h_array (THREAD, array); if (rank > 1) { if (length != 0) { for (int index = 0; index < length; index++) { - ArrayKlass* ak = ArrayKlass::cast(ld_klass); - oop sub_array = ak->multi_allocate(rank-1, &sizes[1], CHECK_NULL); + oop sub_array = ld_klass->multi_allocate(rank - 1, &sizes[1], CHECK_NULL); h_array->obj_at_put(index, sub_array); } } else { @@ -308,7 +305,7 @@ void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, } -Klass* ObjArrayKlass::array_klass(int n, TRAPS) { +ArrayKlass* ObjArrayKlass::array_klass(int n, TRAPS) { assert(dimension() <= n, "check order of chain"); int dim = dimension(); @@ -326,9 +323,8 @@ Klass* ObjArrayKlass::array_klass(int n, TRAPS) { if (higher_dimension() == nullptr) { // Create multi-dim klass object and link them together - Klass* k = + ObjArrayKlass* ak = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this, CHECK_NULL); - ObjArrayKlass* ak = ObjArrayKlass::cast(k); ak->set_lower_dimension(this); // use 'release' to pair with lock-free load release_set_higher_dimension(ak); @@ -337,12 +333,12 @@ Klass* ObjArrayKlass::array_klass(int n, TRAPS) { } } - ObjArrayKlass *ak = ObjArrayKlass::cast(higher_dimension()); + ObjArrayKlass *ak = higher_dimension(); THREAD->check_possible_safepoint(); return ak->array_klass(n, THREAD); } -Klass* ObjArrayKlass::array_klass_or_null(int n) { +ArrayKlass* ObjArrayKlass::array_klass_or_null(int n) { assert(dimension() <= n, "check order of chain"); int dim = dimension(); @@ -353,15 +349,15 @@ Klass* ObjArrayKlass::array_klass_or_null(int n) { return nullptr; } - ObjArrayKlass *ak = ObjArrayKlass::cast(higher_dimension()); + ObjArrayKlass *ak = higher_dimension(); return ak->array_klass_or_null(n); } -Klass* ObjArrayKlass::array_klass(TRAPS) { +ArrayKlass* ObjArrayKlass::array_klass(TRAPS) { return array_klass(dimension() + 1, THREAD); } -Klass* ObjArrayKlass::array_klass_or_null() { +ArrayKlass* ObjArrayKlass::array_klass_or_null() { return array_klass_or_null(dimension() + 1); } diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index 18ebc169258..ea1c1482308 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -97,12 +97,12 @@ class ObjArrayKlass : public ArrayKlass { int length, TRAPS); public: // Returns the ObjArrayKlass for n'th dimension. - virtual Klass* array_klass(int n, TRAPS); - virtual Klass* array_klass_or_null(int n); + virtual ArrayKlass* array_klass(int n, TRAPS); + virtual ArrayKlass* array_klass_or_null(int n); // Returns the array class with this class as element type. - virtual Klass* array_klass(TRAPS); - virtual Klass* array_klass_or_null(); + virtual ArrayKlass* array_klass(TRAPS); + virtual ArrayKlass* array_klass_or_null(); static ObjArrayKlass* cast(Klass* k) { return const_cast(cast(const_cast(k))); diff --git a/src/hotspot/share/oops/typeArrayKlass.cpp b/src/hotspot/share/oops/typeArrayKlass.cpp index e79854147e5..6ce33fd41fb 100644 --- a/src/hotspot/share/oops/typeArrayKlass.cpp +++ b/src/hotspot/share/oops/typeArrayKlass.cpp @@ -171,7 +171,7 @@ void TypeArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos } // create a klass of array holding typeArrays -Klass* TypeArrayKlass::array_klass(int n, TRAPS) { +ArrayKlass* TypeArrayKlass::array_klass(int n, TRAPS) { int dim = dimension(); assert(dim <= n, "check order of chain"); if (dim == n) @@ -198,13 +198,13 @@ Klass* TypeArrayKlass::array_klass(int n, TRAPS) { } } - ObjArrayKlass* h_ak = ObjArrayKlass::cast(higher_dimension()); + ObjArrayKlass* h_ak = higher_dimension(); THREAD->check_possible_safepoint(); return h_ak->array_klass(n, THREAD); } // return existing klass of array holding typeArrays -Klass* TypeArrayKlass::array_klass_or_null(int n) { +ArrayKlass* TypeArrayKlass::array_klass_or_null(int n) { int dim = dimension(); assert(dim <= n, "check order of chain"); if (dim == n) @@ -215,15 +215,15 @@ Klass* TypeArrayKlass::array_klass_or_null(int n) { return nullptr; } - ObjArrayKlass* h_ak = ObjArrayKlass::cast(higher_dimension()); + ObjArrayKlass* h_ak = higher_dimension(); return h_ak->array_klass_or_null(n); } -Klass* TypeArrayKlass::array_klass(TRAPS) { +ArrayKlass* TypeArrayKlass::array_klass(TRAPS) { return array_klass(dimension() + 1, THREAD); } -Klass* TypeArrayKlass::array_klass_or_null() { +ArrayKlass* TypeArrayKlass::array_klass_or_null() { return array_klass_or_null(dimension() + 1); } diff --git a/src/hotspot/share/oops/typeArrayKlass.hpp b/src/hotspot/share/oops/typeArrayKlass.hpp index 48198d55110..47d235da212 100644 --- a/src/hotspot/share/oops/typeArrayKlass.hpp +++ b/src/hotspot/share/oops/typeArrayKlass.hpp @@ -95,12 +95,12 @@ class TypeArrayKlass : public ArrayKlass { public: // Find n'th dimensional array - virtual Klass* array_klass(int n, TRAPS); - virtual Klass* array_klass_or_null(int n); + virtual ArrayKlass* array_klass(int n, TRAPS); + virtual ArrayKlass* array_klass_or_null(int n); // Returns the array class with this class as element type - virtual Klass* array_klass(TRAPS); - virtual Klass* array_klass_or_null(); + virtual ArrayKlass* array_klass(TRAPS); + virtual ArrayKlass* array_klass_or_null(); static TypeArrayKlass* cast(Klass* k) { return const_cast(cast(const_cast(k))); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 0dd92c8b436..abeba1e6b40 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -205,8 +205,8 @@ volatile_nonstatic_field(oopDesc, _metadata._compressed_klass, narrowKlass) \ static_field(BarrierSet, _barrier_set, BarrierSet*) \ nonstatic_field(ArrayKlass, _dimension, int) \ - volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \ - volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \ + volatile_nonstatic_field(ArrayKlass, _higher_dimension, ObjArrayKlass*) \ + volatile_nonstatic_field(ArrayKlass, _lower_dimension, ArrayKlass*) \ nonstatic_field(CompiledICHolder, _holder_metadata, Metadata*) \ nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \ nonstatic_field(ConstantPool, _tags, Array*) \ diff --git a/src/hotspot/share/utilities/tribool.hpp b/src/hotspot/share/utilities/tribool.hpp index 7d5c19d18f5..c61ab1d4d44 100644 --- a/src/hotspot/share/utilities/tribool.hpp +++ b/src/hotspot/share/utilities/tribool.hpp @@ -40,11 +40,15 @@ class TriBool{ public: TriBool() : _value(0) {} - TriBool(bool value) : _value(((u1)value) | 2) {} + TriBool(bool value) : _value(value) { + // set to not-default in separate step to avoid conversion warnings + _value |= 2; + } TriBool(const TriBool& o): _value(o._value) {} TriBool& operator=(bool value) { - _value = ((u1)value) | 2; + _value = value; + _value |= 2; // set to not-default return *this; } @@ -73,7 +77,8 @@ class TriBoolArray { TriBoolAssigner& operator=(bool newval) { _slot ^= ((u1)_value) << _offset; // reset the tribool - _value = (u1)newval| 2; + _value = newval; + _value |= 2; // set to not-default _slot |= ((u1)_value) << _offset; return *this; }; diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java index 8a8ca3009fc..76237df2972 100644 --- a/src/java.base/share/classes/java/text/MessageFormat.java +++ b/src/java.base/share/classes/java/text/MessageFormat.java @@ -948,20 +948,16 @@ public final StringBuffer format(Object arguments, StringBuffer result, * @since 1.4 */ public AttributedCharacterIterator formatToCharacterIterator(Object arguments) { + Objects.requireNonNull(arguments, "arguments must not be null"); StringBuffer result = new StringBuffer(); ArrayList iterators = new ArrayList<>(); - if (arguments == null) { - throw new NullPointerException( - "formatToCharacterIterator must be passed non-null object"); - } subformat((Object[]) arguments, result, null, iterators); if (iterators.size() == 0) { return createAttributedCharacterIterator(""); } return createAttributedCharacterIterator( - iterators.toArray( - new AttributedCharacterIterator[iterators.size()])); + iterators.toArray(new AttributedCharacterIterator[0])); } /** diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 01aff8987ae..625494efc99 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -45,6 +45,7 @@ import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.Sides; import javax.print.attribute.Attribute; import sun.java2d.*; @@ -684,6 +685,24 @@ private Rectangle2D getPageFormatArea(PageFormat page) { return pageFormatArea; } + private int getSides() { + return (this.sidesAttr == null) ? -1 : this.sidesAttr.getValue(); + } + + private void setSides(int sides) { + if (attributes == null) { + return; + } + + final Sides[] sidesTable = new Sides[] {Sides.ONE_SIDED, Sides.TWO_SIDED_LONG_EDGE, Sides.TWO_SIDED_SHORT_EDGE}; + + if (sides >= 0 && sides < sidesTable.length) { + Sides s = sidesTable[sides]; + attributes.add(s); + this.sidesAttr = s; + } + } + private boolean cancelCheck() { // This is called from the native side. diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m index 2c1c4a5e467..9cbd48bf843 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CPrinterJob.m @@ -37,6 +37,10 @@ #import "GeomUtilities.h" #import "JNIUtilities.h" +#define ONE_SIDED 0 +#define TWO_SIDED_LONG_EDGE 1 +#define TWO_SIDED_SHORT_EDGE 2 + static jclass sjc_Paper = NULL; static jclass sjc_PageFormat = NULL; static jclass sjc_CPrinterJob = NULL; @@ -351,6 +355,24 @@ static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrintJob, jobjec [dstPrintInfo setPrinter:printer]; } +static jint duplexModeToSides(PMDuplexMode duplexMode) { + switch(duplexMode) { + case kPMDuplexNone: return ONE_SIDED; + case kPMDuplexTumble: return TWO_SIDED_SHORT_EDGE; + case kPMDuplexNoTumble: return TWO_SIDED_LONG_EDGE; + default: return -1; + } +} + +static PMDuplexMode sidesToDuplexMode(jint sides) { + switch(sides) { + case ONE_SIDED: return kPMDuplexNone; + case TWO_SIDED_SHORT_EDGE: return kPMDuplexTumble; + case TWO_SIDED_LONG_EDGE: return kPMDuplexNoTumble; + default: return kPMDuplexNone; + } +} + static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable) { GET_CPRINTERJOB_CLASS(); @@ -360,6 +382,7 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d DECLARE_METHOD(jm_setPageRangeAttribute, sjc_CPrinterJob, "setPageRangeAttribute", "(IIZ)V"); DECLARE_METHOD(jm_setPrintToFile, sjc_CPrinterJob, "setPrintToFile", "(Z)V"); DECLARE_METHOD(jm_setDestinationFile, sjc_CPrinterJob, "setDestinationFile", "(Ljava/lang/String;)V"); + DECLARE_METHOD(jm_setSides, sjc_CPrinterJob, "setSides", "(I)V"); // get the selected printer's name, and set the appropriate PrintService on the Java side NSString *name = [[src printer] name]; @@ -420,6 +443,12 @@ static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject d jFirstPage, jLastPage, isRangeSet); // AWT_THREADING Safe (known object) CHECK_EXCEPTION(); + PMDuplexMode duplexSetting; + if (PMGetDuplex(src.PMPrintSettings, &duplexSetting) == noErr) { + jint sides = duplexModeToSides(duplexSetting); + (*env)->CallVoidMethod(env, dstPrinterJob, jm_setSides, sides); // AWT_THREADING Safe (known object) + CHECK_EXCEPTION(); + } } } @@ -438,6 +467,8 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj DECLARE_METHOD(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I"); DECLARE_METHOD(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;"); DECLARE_METHOD(jm_getDestinationFile, sjc_CPrinterJob, "getDestinationFile", "()Ljava/lang/String;"); + DECLARE_METHOD(jm_getSides, sjc_CPrinterJob, "getSides", "()I"); + NSMutableDictionary* printingDictionary = [dst dictionary]; @@ -496,6 +527,17 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj } else { [dst setJobDisposition:NSPrintSpoolJob]; } + + jint sides = (*env)->CallIntMethod(env, srcPrinterJob, jm_getSides); + CHECK_EXCEPTION(); + + if (sides >= 0) { + PMDuplexMode duplexMode = sidesToDuplexMode(sides); + PMPrintSettings printSettings = dst.PMPrintSettings; + if (PMSetDuplex(printSettings, duplexMode) == noErr) { + [dst updateFromPMPrintSettings]; + } + } } /* diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index b1b3d00209f..b86d5b88a2a 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -1080,6 +1080,8 @@ public PrintService[] run() { return false; } + this.attributes = attributes; + if (!service.equals(newService)) { try { setPrintService(newService); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp index 608583bdf07..fac9a022209 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp @@ -1790,10 +1790,16 @@ void CCombinedSegTable::GetEUDCFileName(LPWSTR lpszFileName, int cchFileName) DWORD dwBytes = sizeof(szFileName); // try Typeface-specific EUDC font char szTmpName[80]; - VERIFY(::WideCharToMultiByte(CP_ACP, 0, szFamilyName, -1, - szTmpName, sizeof(szTmpName), NULL, NULL)); - LONG lStatus = ::RegQueryValueExA(hKey, (LPCSTR) szTmpName, - NULL, &dwType, szFileName, &dwBytes); + int nb = ::WideCharToMultiByte(CP_ACP, 0, szFamilyName, -1, + szTmpName, sizeof(szTmpName), NULL, NULL); + VERIFY(nb); + + LONG lStatus = 1; + if (nb > 0) { + lStatus = ::RegQueryValueExA(hKey, (LPCSTR) szTmpName, + NULL, &dwType, szFileName, &dwBytes); + } + BOOL fUseDefault = FALSE; if (lStatus != ERROR_SUCCESS){ // try System default EUDC font if (m_fTTEUDCFileExist == FALSE) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp index 9836923fca5..5d3f337036d 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2023, 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 @@ -3925,9 +3925,13 @@ static void throwPrinterException(JNIEnv *env, DWORD err) { sizeof(t_errStr), NULL ); - WideCharToMultiByte(CP_UTF8, 0, t_errStr, -1, + int nb = WideCharToMultiByte(CP_UTF8, 0, t_errStr, -1, errStr, sizeof(errStr), NULL, NULL); - JNU_ThrowByName(env, PRINTEREXCEPTION_STR, errStr); + if (nb > 0) { + JNU_ThrowByName(env, PRINTEREXCEPTION_STR, errStr); + } else { + JNU_ThrowByName(env, PRINTEREXCEPTION_STR, "secondary error during OS message extraction"); + } } diff --git a/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_Charset_Util.cpp b/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_Charset_Util.cpp index 6179d7bbf4b..0f207437523 100644 --- a/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_Charset_Util.cpp +++ b/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_Charset_Util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, 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 @@ -35,16 +35,25 @@ LPSTR UnicodeToUTF8(const LPCWSTR lpUnicodeStr) { DWORD dwUTF8Len = WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, nullptr, 0, nullptr, nullptr); LPSTR lpUTF8Str = new CHAR[dwUTF8Len]; + if (lpUTF8Str == NULL) return NULL; memset(lpUTF8Str, 0, sizeof(CHAR) * (dwUTF8Len)); - WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, lpUTF8Str, dwUTF8Len, nullptr, nullptr); - return lpUTF8Str; + int nb = WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, lpUTF8Str, dwUTF8Len, nullptr, nullptr); + if (nb > 0) { + return lpUTF8Str; + } + delete[] lpUTF8Str; + return NULL; } void UnicodeToUTF8AndCopy(LPSTR dest, LPCWSTR src, SIZE_T maxLength) { LPSTR utf8EncodedName = UnicodeToUTF8(src); - strncpy(dest, utf8EncodedName, maxLength - 1); - delete[] utf8EncodedName; - dest[maxLength - 1] = '\0'; + if (utf8EncodedName != NULL) { + strncpy(dest, utf8EncodedName, maxLength - 1); + delete[] utf8EncodedName; + dest[maxLength - 1] = '\0'; + } else { + if (maxLength > 0) dest[0] = '\0'; + } } #ifdef __cplusplus diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java index 3e41823618f..dabdbd950a8 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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,8 +70,8 @@ public Klass getJavaSuper() { } public long getDimension() { return dimension.getValue(this); } - public Klass getHigherDimension() { return (Klass) higherDimension.getValue(this); } - public Klass getLowerDimension() { return (Klass) lowerDimension.getValue(this); } + public ObjArrayKlass getHigherDimension() { return (ObjArrayKlass) higherDimension.getValue(this); } + public ArrayKlass getLowerDimension() { return (ArrayKlass) lowerDimension.getValue(this); } // constant class names - javaLangCloneable, javaIoSerializable, javaLangObject // Initialized lazily to avoid initialization ordering dependencies between ArrayKlass and String diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java index 3ed168506b9..0075cc77940 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjArrayKlass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -87,7 +87,7 @@ public Klass arrayKlassImpl(boolean orNull, int n) { if (dimension == n) { return this; } - ObjArrayKlass ak = (ObjArrayKlass) getHigherDimension(); + ObjArrayKlass ak = getHigherDimension(); if (ak == null) { if (orNull) return null; // FIXME: would need to change in reflective system to actually diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java index b1ef364fec8..9546d516936 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeArrayKlass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -110,7 +110,7 @@ public Klass arrayKlassImpl(boolean orNull, int n) { } if (dimension == n) return this; - ObjArrayKlass ak = (ObjArrayKlass) getHigherDimension(); + ObjArrayKlass ak = getHigherDimension(); if (ak == null) { if (orNull) return null; // FIXME: would need to change in reflective system to actually diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index 406d163219c..6435bacb998 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -43,6 +43,7 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.TagName; import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import static jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo.Kind.LINK_TYPE_PARAMS; import static jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS; @@ -55,8 +56,9 @@ */ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWriter { - public AbstractExecutableMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) { - super(writer, typeElement); + public AbstractExecutableMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement, + VisibleMemberTable.Kind kind) { + super(writer, typeElement, kind); } public AbstractExecutableMemberWriter(SubWriterHolderWriter writer) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index 347bcff1175..1e059035f42 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -26,9 +26,17 @@ package jdk.javadoc.internal.doclets.formats.html; import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; @@ -43,9 +51,20 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Links; import jdk.javadoc.internal.doclets.toolkit.Resources; +import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.CONSTRUCTORS; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ENUM_CONSTANTS; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.FIELDS; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.METHODS; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.NESTED_CLASSES; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.PROPERTIES; + /** * The base class for member writers. */ @@ -61,21 +80,192 @@ public abstract class AbstractMemberWriter { protected final HtmlIds htmlIds; protected final TypeElement typeElement; + protected final VisibleMemberTable.Kind kind; + protected final VisibleMemberTable visibleMemberTable; - public AbstractMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) { - this.configuration = writer.configuration; - this.options = configuration.getOptions(); + protected final Comparator summariesComparator; + + /** + * The list of {@linkplain VisibleMemberTable.Kind kinds} of summary table + * that appear in the page for any {@linkplain TypeElement type element}. + * + * Note: this is not the default ordering of {@link VisibleMemberTable.Kind}. + * For what it is worth, that ordering is relied on by {@link Navigation}. + * + * Compared to {@link #detailKinds}, this list includes nested classes and distinct + * kinds for required and optional annotation type members + * + * @see VisibleMemberTable.Kind#forSummariesOf(ElementKind) + */ + static final List summaryKinds = List.of( + NESTED_CLASSES, + ENUM_CONSTANTS, PROPERTIES, FIELDS, + CONSTRUCTORS, + ANNOTATION_TYPE_MEMBER_REQUIRED, ANNOTATION_TYPE_MEMBER_OPTIONAL, METHODS + ); + + /** + * The list of {@linkplain VisibleMemberTable.Kind kinds} of detail lists + * that appear in the page for any {@linkplain TypeElement type element}. + * + * Note: this is not the default ordering of {@link VisibleMemberTable.Kind}. + * For what it is worth, that ordering is relied on by {@link Navigation}. + * + * Compared to {@link #summaryKinds}, this list does not include nested classes and + * just a single kind for all annotation type members, although nested classes could + * be included by ensuring that {@link #buildDetails} is a no-op. + * + * @see VisibleMemberTable.Kind#forDetailsOf(ElementKind) + */ + static final List detailKinds = List.of( + ENUM_CONSTANTS, PROPERTIES, FIELDS, + CONSTRUCTORS, + ANNOTATION_TYPE_MEMBER, METHODS + ); + + protected AbstractMemberWriter(ClassWriter writer, VisibleMemberTable.Kind kind) { + this(writer, writer.typeElement, kind); + } + + protected AbstractMemberWriter(SubWriterHolderWriter writer) { + this(writer, null, null); + } + + protected AbstractMemberWriter(SubWriterHolderWriter writer, + TypeElement typeElement, + VisibleMemberTable.Kind kind) { this.writer = writer; this.typeElement = typeElement; + this.kind = kind; + + this.configuration = writer.configuration; + this.options = configuration.getOptions(); this.utils = configuration.utils; this.contents = configuration.getContents(); this.resources = configuration.docResources; this.links = writer.links; this.htmlIds = configuration.htmlIds; + + visibleMemberTable = typeElement == null ? null : configuration.getVisibleMemberTable(typeElement); + + summariesComparator = utils.comparators.indexElementComparator(); + } + + /** + * Builds the list of "details" for all members of this kind. + * + * @param target the content to which the list will be added + */ + public abstract void buildDetails(Content target); + + + /** + * Builds the "summary" for all members of this kind. + * + * @param target the content to which the list will be added + */ + public void buildSummary(Content target) + { + var summaryTreeList = new ArrayList(); + + buildMainSummary(summaryTreeList); + + var showInherited = switch (kind) { + case FIELDS, METHODS, NESTED_CLASSES, PROPERTIES -> true; + case ANNOTATION_TYPE_MEMBER, ANNOTATION_TYPE_MEMBER_OPTIONAL, ANNOTATION_TYPE_MEMBER_REQUIRED, + CONSTRUCTORS, ENUM_CONSTANTS -> false; + }; + if (showInherited) + buildInheritedSummary(summaryTreeList); + + if (!summaryTreeList.isEmpty()) { + Content member = getMemberSummaryHeader(typeElement, target); + summaryTreeList.forEach(member::add); + buildSummary(target, member); + } + } + + /** + * Builds the main summary table for the members of this kind. + * + * @param summaryTreeList the list of contents to which the documentation will be added + */ + private void buildMainSummary(List summaryTreeList) { + Set members = asSortedSet(visibleMemberTable.getVisibleMembers(kind)); + if (!members.isEmpty()) { + var pHelper = writer.getPropertyHelper(); + for (Element member : members) { + final Element property = pHelper.getPropertyElement(member); + if (property != null && member instanceof ExecutableElement ee) { + configuration.cmtUtils.updatePropertyMethodComment(ee, property); + } + if (utils.isMethod(member)) { + var docFinder = utils.docFinder(); + Optional> r = docFinder.search((ExecutableElement) member, (m -> { + var firstSentenceTrees = utils.getFirstSentenceTrees(m); + Optional> optional = firstSentenceTrees.isEmpty() ? Optional.empty() : Optional.of(firstSentenceTrees); + return DocFinder.Result.fromOptional(optional); + })).toOptional(); + // The fact that we use `member` for possibly unrelated tags is suspicious + addMemberSummary(typeElement, member, r.orElse(List.of())); + } else { + addMemberSummary(typeElement, member, utils.getFirstSentenceTrees(member)); + } + } + summaryTreeList.add(getSummaryTable(typeElement)); + } + } + + /** + * Builds the inherited member summary for the members of this kind. + * + * @param targets the list of contents to which the documentation will be added + */ + private void buildInheritedSummary(List targets) { + var inheritedMembersFromMap = asSortedSet(visibleMemberTable.getAllVisibleMembers(kind)); + + for (TypeElement inheritedClass : visibleMemberTable.getVisibleTypeElements()) { + if (!(utils.isPublic(inheritedClass) || utils.isLinkable(inheritedClass))) { + continue; + } + if (Objects.equals(inheritedClass, typeElement)) { + continue; + } + if (utils.hasHiddenTag(inheritedClass)) { + continue; + } + + List members = inheritedMembersFromMap.stream() + .filter(e -> Objects.equals(utils.getEnclosingTypeElement(e), inheritedClass)) + .toList(); + + if (!members.isEmpty()) { + SortedSet inheritedMembers = new TreeSet<>(summariesComparator); + inheritedMembers.addAll(members); + Content inheritedHeader = getInheritedSummaryHeader(inheritedClass); + Content links = getInheritedSummaryLinks(); + addSummaryFootNote(inheritedClass, inheritedMembers, links); + inheritedHeader.add(links); + targets.add(inheritedHeader); + } + } + } + + private void addSummaryFootNote(TypeElement inheritedClass, Iterable inheritedMembers, + Content links) { + boolean isFirst = true; + for (Element member : inheritedMembers) { + TypeElement t = utils.isUndocumentedEnclosure(inheritedClass) + ? typeElement : inheritedClass; + addInheritedMemberSummary(t, member, isFirst, links); + isFirst = false; + } } - public AbstractMemberWriter(SubWriterHolderWriter writer) { - this(writer, null); + private SortedSet asSortedSet(Collection members) { + SortedSet out = new TreeSet<>(summariesComparator); + out.addAll(members); + return out; } /** @@ -93,7 +283,7 @@ public AbstractMemberWriter(SubWriterHolderWriter writer) { * @param summariesList the list of summaries * @param content the summary */ - public abstract void addSummary(Content summariesList, Content content); + public abstract void buildSummary(Content summariesList, Content content); /** * Returns a list of visible elements of the specified kind in this @@ -375,7 +565,7 @@ protected void serialWarning(Element e, String key, String a1, String a2) { public void addMemberSummary(TypeElement tElement, Element member, List firstSentenceTrees) { if (tElement != typeElement) { - throw new IllegalStateException(tElement + ", " + typeElement); + throw new IllegalStateException(getClass() + ": " + tElement + ", " + typeElement); } var table = getSummaryTable(); List rowContents = new ArrayList<>(); @@ -398,11 +588,10 @@ public void addMemberSummary(TypeElement tElement, Element member, * @param tElement the class the inherited member belongs to * @param member the inherited member that is being documented * @param isFirst true if this is the first member in the list - * @param isLast true if this is the last member in the list * @param content the content to which the links will be added */ public void addInheritedMemberSummary(TypeElement tElement, - Element member, boolean isFirst, boolean isLast, + Element member, boolean isFirst, Content content) { writer.addInheritedMemberSummary(this, tElement, member, isFirst, content); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java index 2968ce29897..d0483d5d33c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java @@ -122,7 +122,7 @@ protected void addExtendsImplements(TypeElement parent, TypeElement typeElement, Content content) { - SortedSet interfaces = new TreeSet<>(comparators.makeGeneralPurposeComparator()); + SortedSet interfaces = new TreeSet<>(comparators.generalPurposeComparator()); typeElement.getInterfaces().forEach(t -> interfaces.add(utils.asTypeElement(t))); if (interfaces.size() > (utils.isPlainInterface(typeElement) ? 1 : 0)) { boolean isFirst = true; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java index ad39bceea8b..5ca24fac177 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java @@ -38,7 +38,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; -import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; @@ -47,50 +46,34 @@ */ public class AnnotationTypeMemberWriter extends AbstractMemberWriter { - /** - * We generate separate summaries for required and optional annotation interface members, - * so we need dedicated writer instances for each kind. For the details section, a single - * shared list is generated so a special {@code ANY} value is provided for this case. - */ - enum Kind { - OPTIONAL, - REQUIRED, - ANY - } - - private final Kind kind; - /** * The index of the current member that is being documented at this point * in time. */ protected Element currentMember; - /** - * Constructs a new AnnotationTypeMemberWriterImpl for any kind of member. - * - * @param writer The writer for the class that the member belongs to. - */ - public AnnotationTypeMemberWriter(SubWriterHolderWriter writer) { - super(writer); - this.kind = Kind.ANY; - } - /** * Constructs a new AnnotationTypeMemberWriterImpl for a specific kind of member. * + * We generate separate summaries for required and optional annotation interface members, + * so we need dedicated writer instances for each kind. For the details section, a single + * shared list is generated + * * @param writer the writer that will write the output. - * @param annotationType the AnnotationType that holds this member. * @param kind the kind of annotation interface members to handle. */ - public AnnotationTypeMemberWriter(SubWriterHolderWriter writer, - TypeElement annotationType, - Kind kind) { - super(writer, annotationType); - this.kind = kind; + public AnnotationTypeMemberWriter(ClassWriter writer, VisibleMemberTable.Kind kind) { + super(writer, kind); + assert switch (kind) { + case ANNOTATION_TYPE_MEMBER_REQUIRED, + ANNOTATION_TYPE_MEMBER_OPTIONAL, + ANNOTATION_TYPE_MEMBER -> true; + default -> false; + }; } - public void build(Content target) throws DocletException { + @Override + public void buildDetails(Content target) { buildAnnotationTypeMember(target); } @@ -191,13 +174,13 @@ protected void buildDefaultValueInfo(Content annotationContent) { public Content getMemberSummaryHeader(TypeElement typeElement, Content content) { switch (kind) { - case OPTIONAL -> content.add(selectComment( - MarkerComments.START_OF_ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY, - MarkerComments.START_OF_ANNOTATION_INTERFACE_OPTIONAL_MEMBER_SUMMARY)); - case REQUIRED -> content.add(selectComment( + case ANNOTATION_TYPE_MEMBER_REQUIRED -> content.add(selectComment( MarkerComments.START_OF_ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY, MarkerComments.START_OF_ANNOTATION_INTERFACE_REQUIRED_MEMBER_SUMMARY)); - case ANY -> throw new UnsupportedOperationException("unsupported member kind"); + case ANNOTATION_TYPE_MEMBER_OPTIONAL -> content.add(selectComment( + MarkerComments.START_OF_ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY, + MarkerComments.START_OF_ANNOTATION_INTERFACE_OPTIONAL_MEMBER_SUMMARY)); + default -> throw new IllegalStateException(kind.toString()); } Content c = new ContentBuilder(); writer.addSummaryHeader(this, c); @@ -209,12 +192,12 @@ protected Content getMemberHeader() { } @Override - public void addSummary(Content summariesList, Content content) { + public void buildSummary(Content summariesList, Content content) { writer.addSummary(HtmlStyle.memberSummary, switch (kind) { - case REQUIRED -> HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY; - case OPTIONAL -> HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY; - case ANY -> throw new UnsupportedOperationException("unsupported member kind"); + case ANNOTATION_TYPE_MEMBER_REQUIRED -> HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY; + case ANNOTATION_TYPE_MEMBER_OPTIONAL -> HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY; + default -> throw new IllegalStateException(kind.toString()); }, summariesList, content); } @@ -274,9 +257,9 @@ protected Content getAnnotationDetails(Content annotationDetailsHeader, Content public void addSummaryLabel(Content content) { var label = HtmlTree.HEADING(Headings.TypeDeclaration.SUMMARY_HEADING, switch (kind) { - case REQUIRED -> contents.annotateTypeRequiredMemberSummaryLabel; - case OPTIONAL -> contents.annotateTypeOptionalMemberSummaryLabel; - case ANY -> throw new UnsupportedOperationException("unsupported member kind"); + case ANNOTATION_TYPE_MEMBER_REQUIRED -> contents.annotateTypeRequiredMemberSummaryLabel; + case ANNOTATION_TYPE_MEMBER_OPTIONAL -> contents.annotateTypeOptionalMemberSummaryLabel; + default -> throw new IllegalStateException(kind.toString()); }); content.add(label); } @@ -288,9 +271,9 @@ public void addSummaryLabel(Content content) { protected Content getCaption() { return contents.getContent( switch (kind) { - case REQUIRED -> "doclet.Annotation_Type_Required_Members"; - case OPTIONAL -> "doclet.Annotation_Type_Optional_Members"; - case ANY -> throw new UnsupportedOperationException("unsupported member kind"); + case ANNOTATION_TYPE_MEMBER_REQUIRED -> "doclet.Annotation_Type_Required_Members"; + case ANNOTATION_TYPE_MEMBER_OPTIONAL -> "doclet.Annotation_Type_Optional_Members"; + default -> throw new IllegalStateException(kind.toString()); }); } @@ -298,9 +281,9 @@ protected Content getCaption() { public TableHeader getSummaryTableHeader(Element member) { return new TableHeader(contents.modifierAndTypeLabel, switch (kind) { - case REQUIRED -> contents.annotationTypeRequiredMemberLabel; - case OPTIONAL -> contents.annotationTypeOptionalMemberLabel; - case ANY -> throw new UnsupportedOperationException("unsupported member kind"); + case ANNOTATION_TYPE_MEMBER_REQUIRED -> contents.annotationTypeRequiredMemberLabel; + case ANNOTATION_TYPE_MEMBER_OPTIONAL -> contents.annotationTypeOptionalMemberLabel; + default -> throw new IllegalStateException(kind.toString()); }, contents.descriptionLabel); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java index 0be5dba6980..a136b690727 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java @@ -96,11 +96,11 @@ public ClassUseWriter(HtmlConfiguration configuration, super(configuration, filename); this.typeElement = typeElement; if (mapper.classToPackageAnnotations.containsKey(typeElement)) { - pkgToPackageAnnotations = new TreeSet<>(comparators.makeClassUseComparator()); + pkgToPackageAnnotations = new TreeSet<>(comparators.classUseComparator()); pkgToPackageAnnotations.addAll(mapper.classToPackageAnnotations.get(typeElement)); } configuration.currentTypeElement = typeElement; - this.pkgSet = new TreeSet<>(comparators.makePackageComparator()); + this.pkgSet = new TreeSet<>(comparators.packageComparator()); this.pkgToClassTypeParameter = pkgDivide(mapper.classToClassTypeParam); this.pkgToClassAnnotations = pkgDivide(mapper.classToClassAnnotations); this.pkgToMethodTypeParameter = pkgDivide(mapper.classToMethodTypeParam); @@ -170,7 +170,7 @@ private Map> pkgDivide(Map> map = new HashMap<>(); List elements = classMap.get(typeElement); if (elements != null) { - elements.sort(comparators.makeClassUseComparator()); + elements.sort(comparators.classUseComparator()); for (Element e : elements) { PackageElement pkg = utils.containingPackage(e); pkgSet.add(pkg); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java index 4028285de15..6affe6ff61b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java @@ -27,11 +27,7 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -65,19 +61,9 @@ import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; -import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.CONSTRUCTORS; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ENUM_CONSTANTS; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.FIELDS; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.METHODS; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.NESTED_CLASSES; -import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.PROPERTIES; - /** * Generate the Class Information Page. * @@ -99,9 +85,7 @@ public class ClassWriter extends SubWriterHolderWriter { protected final VisibleMemberTable visibleMemberTable; protected final ClassTree classTree; - - private final Comparator summariesComparator; - private final PropertyUtils.PropertyHelper pHelper; + protected final PropertyUtils.PropertyHelper pHelper; /** * @param configuration the configuration data for the doclet @@ -116,7 +100,6 @@ public ClassWriter(HtmlConfiguration configuration, TypeElement typeElement, this.classTree = classTree; visibleMemberTable = configuration.getVisibleMemberTable(typeElement); - summariesComparator = utils.comparators.makeIndexElementComparator(); pHelper = new PropertyUtils.PropertyHelper(configuration, typeElement); switch (typeElement.getKind()) { @@ -125,6 +108,11 @@ public ClassWriter(HtmlConfiguration configuration, TypeElement typeElement, } } + @Override + public PropertyUtils.PropertyHelper getPropertyHelper() { + return pHelper; + } + public void build() throws DocletException { buildClassDoc(); } @@ -172,7 +160,7 @@ protected void buildClassTree(Content classContent) { * @param target the content to which the documentation will be added */ protected void buildClassInfo(Content target) { - Content c = getOutputInstance(); + Content c = new ContentBuilder(); buildParamInfo(c); buildSuperInterfacesInfo(c); buildImplementedInterfacesInfo(c); @@ -286,7 +274,7 @@ private void copyDocFiles() throws DocletException { //package already. Otherwise, we are making duplicate copies. var docFilesHandler = configuration .getWriterFactory() - .getDocFilesHandler(containingPackage); + .newDocFilesHandler(containingPackage); docFilesHandler.copyDocFiles(); containingPackagesSeen.add(containingPackage); } @@ -326,323 +314,33 @@ protected void buildClassTagInfo(Content target) { */ protected void buildMemberSummary(Content classContent) { Content summariesList = getSummariesList(); - buildSummaries(summariesList); - classContent.add(getMemberSummary(summariesList)); - } - - protected void buildSummaries(Content target) { - buildPropertiesSummary(target); - buildNestedClassesSummary(target); - buildEnumConstantsSummary(target); - buildAnnotationTypeRequiredMemberSummary(target); - buildAnnotationTypeOptionalMemberSummary(target); - buildFieldsSummary(target); - buildConstructorsSummary(target); - buildMethodsSummary(target); - } - - /** - * Builds the summary for any optional members of an annotation type. - * - * @param summariesList the list of summaries to which the summary will be added - */ - protected void buildAnnotationTypeOptionalMemberSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(ANNOTATION_TYPE_MEMBER_OPTIONAL); - var writerFactory = configuration.getWriterFactory(); - var writer = writerFactory.getAnnotationTypeOptionalMemberWriter(this); - addSummary(writer, ANNOTATION_TYPE_MEMBER_OPTIONAL, false, summariesList); - } - - /** - * Builds the summary for any required members of an annotation type. - * - * @param summariesList the list of summaries to which the summary will be added - */ - protected void buildAnnotationTypeRequiredMemberSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(ANNOTATION_TYPE_MEMBER_REQUIRED); - var writerFactory = configuration.getWriterFactory(); - var writer = writerFactory.getAnnotationTypeRequiredMemberWriter(this); - addSummary(writer, ANNOTATION_TYPE_MEMBER_REQUIRED, false, summariesList); - } - - /** - * Builds the summary for any enum constants of an enum type. - * - * @param summariesList the list of summaries to which the summary will be added - */ - protected void buildEnumConstantsSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(ENUM_CONSTANTS); - var writerFactory = configuration.getWriterFactory(); - var writer = writerFactory.getEnumConstantWriter(this); - addSummary(writer, ENUM_CONSTANTS, false, summariesList); - } - - /** - * Builds the summary for any fields. - * - * @param summariesList the list of summaries to which the summary will be added - */ - protected void buildFieldsSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(FIELDS); - var writerFactory = configuration.getWriterFactory(); - var writer = writerFactory.getFieldWriter(this); - addSummary(writer, FIELDS, true, summariesList); - } - - /** - * Builds the summary for any properties. - * - * @param summariesList the list of summaries to which the summary will be added - */ - protected void buildPropertiesSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(PROPERTIES); - var writerFactory = configuration.getWriterFactory(); - var writer = writerFactory.getPropertyWriter(this); - addSummary(writer, PROPERTIES, true, summariesList); - } - - /** - * Builds the summary for any nested classes. - * - * @param summariesList the list of summaries to which the summary will be added - */ - protected void buildNestedClassesSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(NESTED_CLASSES); - var writerFactory = configuration.getWriterFactory(); - var writer = new NestedClassWriter(this, typeElement); // TODO: surprising omission from WriterFactory - addSummary(writer, NESTED_CLASSES, true, summariesList); - } - - /** - * Builds the summary for any methods. - * - * @param summariesList the content to which the documentation will be added - */ - protected void buildMethodsSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(METHODS); - var writerFactory = configuration.getWriterFactory(); - var writer = writerFactory.getMethodWriter(this); - addSummary(writer, METHODS, true, summariesList); - } - - /** - * Builds the summary for any constructors. - * - * @param summariesList the content to which the documentation will be added - */ - protected void buildConstructorsSummary(Content summariesList) { -// MemberSummaryWriter writer = memberSummaryWriters.get(CONSTRUCTORS); - var writerFactory = configuration.getWriterFactory(); - var writer = writerFactory.getConstructorWriter(this); - addSummary(writer, CONSTRUCTORS, false, summariesList); - } - - - /** - * Adds the summary for the documentation. - * - * @param writer the writer for this member summary - * @param kind the kind of members to document - * @param showInheritedSummary true if a summary of any inherited elements should be documented - * @param summariesList the list of summaries to which the summary will be added - */ - private void addSummary(AbstractMemberWriter writer, - VisibleMemberTable.Kind kind, - boolean showInheritedSummary, - Content summariesList) - { - // TODO: could infer the writer from the kind - // TODO: why LinkedList? - List summaryTreeList = new LinkedList<>(); - buildSummary(writer, kind, summaryTreeList); - if (showInheritedSummary) - buildInheritedSummary(writer, kind, summaryTreeList); - if (!summaryTreeList.isEmpty()) { - Content member = writer.getMemberSummaryHeader(typeElement, summariesList); - summaryTreeList.forEach(member::add); - writer.addSummary(summariesList, member); - } - } - - /** - * Build the member summary for the given members. - * - * @param writer the summary writer to write the output. - * @param kind the kind of members to summarize. - * @param summaryTreeList the list of contents to which the documentation will be added - */ - private void buildSummary(AbstractMemberWriter writer, - VisibleMemberTable.Kind kind, List summaryTreeList) { - SortedSet members = asSortedSet(visibleMemberTable.getVisibleMembers(kind)); - if (!members.isEmpty()) { - for (Element member : members) { - final Element property = pHelper.getPropertyElement(member); - if (property != null && member instanceof ExecutableElement ee) { - configuration.cmtUtils.updatePropertyMethodComment(ee, property); - } - if (utils.isMethod(member)) { - var docFinder = utils.docFinder(); - Optional> r = docFinder.search((ExecutableElement) member, (m -> { - var firstSentenceTrees = utils.getFirstSentenceTrees(m); - Optional> optional = firstSentenceTrees.isEmpty() ? Optional.empty() : Optional.of(firstSentenceTrees); - return DocFinder.Result.fromOptional(optional); - })).toOptional(); - // The fact that we use `member` for possibly unrelated tags is suspicious - writer.addMemberSummary(typeElement, member, r.orElse(List.of())); - } else { - writer.addMemberSummary(typeElement, member, utils.getFirstSentenceTrees(member)); - } - } - summaryTreeList.add(writer.getSummaryTable(typeElement)); - } - } - - /** - * Build the inherited member summary for the given methods. - * - * @param writer the writer for this member summary. - * @param kind the kind of members to document. - * @param targets the list of contents to which the documentation will be added - */ - private void buildInheritedSummary(AbstractMemberWriter writer, - VisibleMemberTable.Kind kind, List targets) { - SortedSet inheritedMembersFromMap = asSortedSet(visibleMemberTable.getAllVisibleMembers(kind)); - for (TypeElement inheritedClass : visibleMemberTable.getVisibleTypeElements()) { - if (!(utils.isPublic(inheritedClass) || utils.isLinkable(inheritedClass))) { - continue; - } - if (Objects.equals(inheritedClass, typeElement)) { - continue; - } - if (utils.hasHiddenTag(inheritedClass)) { - continue; - } - - List members = inheritedMembersFromMap.stream() - .filter(e -> Objects.equals(utils.getEnclosingTypeElement(e), inheritedClass)) - .toList(); - - if (!members.isEmpty()) { - SortedSet inheritedMembers = new TreeSet<>(summariesComparator); - inheritedMembers.addAll(members); - Content inheritedHeader = writer.getInheritedSummaryHeader(inheritedClass); - Content links = writer.getInheritedSummaryLinks(); - addSummaryFootNote(inheritedClass, inheritedMembers, links, writer); - inheritedHeader.add(links); - targets.add(inheritedHeader); - } + var f = configuration.getWriterFactory(); + for (var k : AbstractMemberWriter.summaryKinds) { + var writer = f.newMemberWriter(this, k); + writer.buildSummary(summariesList); } - } - - private void addSummaryFootNote(TypeElement inheritedClass, Iterable inheritedMembers, - Content links, AbstractMemberWriter writer) { - boolean isFirst = true; - for (var iterator = inheritedMembers.iterator(); iterator.hasNext(); ) { - var member = iterator.next(); - TypeElement t = utils.isUndocumentedEnclosure(inheritedClass) - ? typeElement : inheritedClass; - writer.addInheritedMemberSummary(t, member, isFirst, !iterator.hasNext(), links); - isFirst = false; - } - } - private SortedSet asSortedSet(Collection members) { - SortedSet out = new TreeSet<>(summariesComparator); - out.addAll(members); - return out; + classContent.add(getMemberSummary(summariesList)); } /** * Build the member details contents of the page. * * @param classContent the content to which the documentation will be added - * @throws DocletException if there is a problem while building the documentation */ - protected void buildMemberDetails(Content classContent) throws DocletException { + protected void buildMemberDetails(Content classContent) { Content detailsList = getDetailsList(); - buildEnumConstantsDetails(detailsList); - buildPropertyDetails(detailsList); - buildFieldDetails(detailsList); - buildConstructorDetails(detailsList); - buildAnnotationTypeMemberDetails(detailsList); - buildMethodDetails(detailsList); + var f = configuration.getWriterFactory(); + for (var k : AbstractMemberWriter.detailKinds) { + var writer = f.newMemberWriter(this, k); + writer.buildDetails(detailsList); + } classContent.add(getMemberDetails(detailsList)); } - /** - * Build the enum constants documentation. - * - * @param detailsList the content to which the documentation will be added - */ - protected void buildEnumConstantsDetails(Content detailsList) { - var writerFactory = configuration.getWriterFactory(); - var enumConstantWriter = writerFactory.getEnumConstantWriter(this); - enumConstantWriter.build(detailsList); - } - - /** - * Build the field documentation. - * - * @param detailsList the content to which the documentation will be added - * @throws DocletException if there is a problem while building the documentation - */ - protected void buildFieldDetails(Content detailsList) throws DocletException { - var writerFactory = configuration.getWriterFactory(); - var fieldWriter = writerFactory.getFieldWriter(this); - fieldWriter.build(detailsList); - } - - /** - * Build the property documentation. - * - * @param detailsList the content to which the documentation will be added - */ - public void buildPropertyDetails( Content detailsList) { - var writerFactory = configuration.getWriterFactory(); - var propertyWriter = writerFactory.getPropertyWriter(this); - propertyWriter.build(detailsList); - } - - /** - * Build the constructor documentation. - * - * @param detailsList the content to which the documentation will be added - * @throws DocletException if there is a problem while building the documentation - */ - protected void buildConstructorDetails(Content detailsList) throws DocletException { - var writerFactory = configuration.getWriterFactory(); - var constructorWriter = writerFactory.getConstructorWriter(this); - constructorWriter.build(detailsList); - } - - /** - * Build the method documentation. - * - * @param detailsList the content to which the documentation will be added - * @throws DocletException if there is a problem while building the documentation - */ - protected void buildMethodDetails(Content detailsList) throws DocletException { - var writerFactory = configuration.getWriterFactory(); - var methodWriter = writerFactory.getMethodWriter(this); - methodWriter.build(detailsList); - } - - /** - * Build the annotation type optional member documentation. - * - * @param target the content to which the documentation will be added - * @throws DocletException if there is a problem building the documentation - */ - protected void buildAnnotationTypeMemberDetails(Content target) - throws DocletException { - var writerFactory = configuration.getWriterFactory(); - var annotationTypeMemberWriter = writerFactory.getAnnotationTypeMemberWriter(this); - annotationTypeMemberWriter.build(target); - } - /** * The documentation for values() and valueOf() in Enums are set by the * doclet only iff the user or overridden methods are missing. @@ -734,12 +432,6 @@ private void setRecordDocumentation(TypeElement elem) { } } } - - } - - // TODO: inline this - public Content getOutputInstance() { - return new ContentBuilder(); } protected Content getHeader(String header) { @@ -963,7 +655,7 @@ protected void addInterfaceUsageInfo(Content target) { } protected void addImplementedInterfacesInfo(Content target) { - SortedSet interfaces = new TreeSet<>(comparators.makeTypeMirrorClassUseComparator()); + SortedSet interfaces = new TreeSet<>(comparators.typeMirrorClassUseComparator()); interfaces.addAll(utils.getAllInterfaces(typeElement)); if (utils.isClass(typeElement) && !interfaces.isEmpty()) { var dl = HtmlTree.DL(HtmlStyle.notes); @@ -975,7 +667,7 @@ protected void addImplementedInterfacesInfo(Content target) { protected void addSuperInterfacesInfo(Content target) { SortedSet interfaces = - new TreeSet<>(comparators.makeTypeMirrorIndexUseComparator()); + new TreeSet<>(comparators.typeMirrorIndexUseComparator()); interfaces.addAll(utils.getAllInterfaces(typeElement)); if (utils.isPlainInterface(typeElement) && !interfaces.isEmpty()) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java index 62de9508364..6feded28c07 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java @@ -309,7 +309,7 @@ protected SortedSet members() { members.addAll(vmt.getVisibleMembers(VisibleMemberTable.Kind.FIELDS)); members.addAll(vmt.getVisibleMembers(VisibleMemberTable.Kind.ENUM_CONSTANTS)); SortedSet includes = - new TreeSet<>(utils.comparators.makeGeneralPurposeComparator()); + new TreeSet<>(utils.comparators.generalPurposeComparator()); for (Element element : members) { VariableElement member = (VariableElement)element; if (member.getConstantValue() != null) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java index 9a893f63b90..1bc1b71a6a0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java @@ -40,7 +40,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; -import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; @@ -62,7 +61,7 @@ public class ConstructorWriter extends AbstractExecutableMemberWriter { * @param writer The writer for the class that the constructors belong to. */ public ConstructorWriter(ClassWriter writer) { - super(writer, writer.getTypeElement()); + super(writer, writer.typeElement, VisibleMemberTable.Kind.CONSTRUCTORS); // the following must be done before the summary table is generated var constructors = getVisibleMembers(VisibleMemberTable.Kind.CONSTRUCTORS); @@ -82,7 +81,8 @@ public ConstructorWriter(SubWriterHolderWriter writer) { super(writer); } - public void build(Content target) throws DocletException { + @Override + public void buildDetails(Content target) { buildConstructorDoc(target); } @@ -178,7 +178,7 @@ public Content getMemberSummaryHeader(TypeElement typeElement, } @Override - public void addSummary(Content summariesList, Content content) { + public void buildSummary(Content summariesList, Content content) { writer.addSummary(HtmlStyle.constructorSummary, HtmlIds.CONSTRUCTOR_SUMMARY, summariesList, content); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java index d00bf986ad6..2cfb32b4322 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java @@ -47,14 +47,15 @@ public class EnumConstantWriter extends AbstractMemberWriter { private VariableElement currentElement; public EnumConstantWriter(ClassWriter classWriter) { - super(classWriter, classWriter.typeElement); + super(classWriter, classWriter.typeElement, VisibleMemberTable.Kind.ENUM_CONSTANTS); } public EnumConstantWriter(SubWriterHolderWriter writer) { super(writer); } - public void build(Content target) { + @Override + public void buildDetails(Content target) { buildEnumConstant(target); } @@ -147,7 +148,7 @@ public Content getMemberSummaryHeader(TypeElement typeElement, } @Override - public void addSummary(Content summariesList, Content content) { + public void buildSummary(Content summariesList, Content content) { writer.addSummary(HtmlStyle.constantsSummary, HtmlIds.ENUM_CONSTANT_SUMMARY, summariesList, content); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java index 34658d0448d..e97239340aa 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java @@ -38,7 +38,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; -import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; /** @@ -53,11 +52,11 @@ public class FieldWriter extends AbstractMemberWriter { private VariableElement currentElement; public FieldWriter(ClassWriter writer) { - super(writer, writer.typeElement); + super(writer, VisibleMemberTable.Kind.FIELDS); } public FieldWriter(SubWriterHolderWriter writer, TypeElement typeElement) { - super(writer, typeElement); + super(writer, typeElement, VisibleMemberTable.Kind.FIELDS); } // used in ClassUseWriter and SummaryUseWriter @@ -65,7 +64,8 @@ public FieldWriter(SubWriterHolderWriter writer) { super(writer); } - public void build(Content target) throws DocletException { + @Override + public void buildDetails(Content target) { buildFieldDoc(target); } @@ -156,7 +156,7 @@ public Content getMemberSummaryHeader(TypeElement typeElement, } @Override - public void addSummary(Content summariesList, Content content) { + public void buildSummary(Content summariesList, Content content) { writer.addSummary(HtmlStyle.fieldSummary, HtmlIds.FIELD_SUMMARY, summariesList, content); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java index b90fde1bae2..102c2e31e20 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java @@ -186,7 +186,7 @@ public enum ConditionalPage { /** * The set of packages for which we have copied the doc files. */ - private Set containingPackagesSeen; + private final Set containingPackagesSeen; /** * Constructs the full configuration needed by the doclet, including @@ -239,6 +239,7 @@ public HtmlConfiguration(Doclet doclet, Locale locale, Reporter reporter) { conditionalPages = EnumSet.noneOf(ConditionalPage.class); } + @Override protected void initConfiguration(DocletEnvironment docEnv, Function resourceKeyMapper) { super.initConfiguration(docEnv, resourceKeyMapper); @@ -280,7 +281,7 @@ public HtmlOptions getOptions() { /** * {@return the packages for which we have copied the doc files} * - * @see {@link ClassWriter#copyDocFiles()} + * @see ClassWriter#copyDocFiles() */ public Set getContainingPackagesSeen() { return containingPackagesSeen; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index 9daf109182f..f644483dffb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -101,6 +101,11 @@ public String getName() { */ private Messages messages; + /** + * Factory for page- and member-writers. + */ + private WriterFactory writerFactory; + /** * Base path for resources for this doclet. */ @@ -111,6 +116,7 @@ public String getName() { public void init(Locale locale, Reporter reporter) { configuration = new HtmlConfiguration(initiatingDoclet, locale, reporter); messages = configuration.getMessages(); + writerFactory = configuration.getWriterFactory(); } /** @@ -203,8 +209,6 @@ public void generateClassFiles(ClassTree classTree) throws DocletException { * TreeWriter generation first to ensure the Class Hierarchy is built * first and then can be used in the later generation. * - * For new format. - * * @throws DocletException if there is a problem while writing the other files */ @Override // defined by AbstractDoclet @@ -212,8 +216,8 @@ protected void generateOtherFiles(ClassTree classTree) throws DocletException { super.generateOtherFiles(classTree); - new ConstantsSummaryWriter(configuration).build(); - new SerializedFormWriter(configuration).build(); + writerFactory.newConstantsSummaryWriter().build(); + writerFactory.newSerializedFormWriter().build(); var options = configuration.getOptions(); if (options.linkSource()) { @@ -395,7 +399,7 @@ protected void generateClassFiles(SortedSet typeElems, ClassTree cl !(configuration.isGeneratedDoc(te) && utils.isIncluded(te))) { continue; } - new ClassWriter(configuration, te, classTree).build(); + writerFactory.newClassWriter(te, classTree).build(); } } @@ -404,7 +408,7 @@ protected void generateModuleFiles() throws DocletException { if (configuration.showModules) { List mdles = new ArrayList<>(configuration.modulePackages.keySet()); for (ModuleElement mdle : mdles) { - new ModuleWriter(configuration, mdle).build(); + writerFactory.newModuleWriter(mdle).build(); } } } @@ -419,7 +423,7 @@ protected void generatePackageFiles(ClassTree classTree) throws DocletException // deprecated, do not generate the package-summary.html, package-frame.html // and package-tree.html pages for that package. if (!(options.noDeprecated() && utils.isDeprecated(pkg))) { - new PackageWriter(configuration, pkg).build(); + writerFactory.newPackageWriter(pkg).build(); if (options.createTree()) { PackageTreeWriter.generate(configuration, pkg, options.noDeprecated()); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index b74d9663b1f..7d210d2d1ba 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -2039,7 +2039,7 @@ private List getModuleStylesheets(PackageElement pkgElement) throws private List getStylesheets(Element element) throws DocFileIOException { List localStylesheets = configuration.localStylesheetMap.get(element); if (localStylesheets == null) { - DocFilesHandler docFilesHandler = configuration.getWriterFactory().getDocFilesHandler(element); + DocFilesHandler docFilesHandler = configuration.getWriterFactory().newDocFilesHandler(element); localStylesheets = docFilesHandler.getStylesheets(); configuration.localStylesheetMap.put(element, localStylesheets); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java index 5602bb614e7..e45e3b33f70 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java @@ -35,7 +35,6 @@ import javax.lang.model.element.TypeElement; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Links; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; @@ -77,6 +76,7 @@ public class HtmlIndexBuilder extends IndexBuilder { * After the initial work to add the element items, the remaining fields in * the items are also initialized. */ + @Override public void addElements() { super.addElements(); if (classesOnly) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java index 8c73e1d60a6..e1974a05858 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java @@ -42,7 +42,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; -import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; @@ -64,7 +63,7 @@ public class MethodWriter extends AbstractExecutableMemberWriter { * @param writer the writer for the class that the methods belong to.\ */ public MethodWriter(ClassWriter writer) { - super(writer, writer.typeElement); + super(writer, writer.typeElement, VisibleMemberTable.Kind.METHODS); } /** @@ -74,7 +73,7 @@ public MethodWriter(ClassWriter writer) { * @param typeElement the class */ public MethodWriter(SubWriterHolderWriter writer, TypeElement typeElement) { - super(writer, typeElement); + super(writer, typeElement, VisibleMemberTable.Kind.METHODS); } /** @@ -87,7 +86,8 @@ public MethodWriter(SubWriterHolderWriter writer) { super(writer); } - public void build(Content target) throws DocletException { + @Override + public void buildDetails(Content target) { buildMethodDoc(target); } @@ -182,7 +182,7 @@ public Content getMemberSummaryHeader(TypeElement typeElement, Content target) { } @Override - public void addSummary(Content summariesList, Content content) { + public void buildSummary(Content summariesList, Content content) { writer.addSummary(HtmlStyle.methodSummary, HtmlIds.METHOD_SUMMARY, summariesList, content); } @@ -399,7 +399,7 @@ protected static void addImplementsInfo(HtmlDocletWriter writer, var enclosing = (TypeElement) method.getEnclosingElement(); VisibleMemberTable vmt = writer.configuration.getVisibleMemberTable(enclosing); SortedSet implementedMethods = - new TreeSet<>(utils.comparators.makeOverrideUseComparator()); + new TreeSet<>(utils.comparators.overrideUseComparator()); implementedMethods.addAll(methods); for (ExecutableElement implementedMeth : implementedMethods) { TypeMirror intfac = vmt.getImplementedMethodHolder(method, implementedMeth); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java index dd8f3b4cd84..db38bbbaaa2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java @@ -75,13 +75,13 @@ public class ModuleWriter extends HtmlDocletWriter { * Map of module elements and modifiers required by this module. */ private final Map requires - = new TreeMap<>(comparators.makeModuleComparator()); + = new TreeMap<>(comparators.moduleComparator()); /** * Map of indirect modules and modifiers, transitive closure, required by this module. */ private final Map indirectModules - = new TreeMap<>(comparators.makeModuleComparator()); + = new TreeMap<>(comparators.moduleComparator()); /** * Details about a package in a module. @@ -111,44 +111,44 @@ static class PackageEntry { /** * Map of packages of this module, and details of whether they are exported or opened. */ - private final Map packages = new TreeMap<>(utils.comparators.makePackageComparator()); + private final Map packages = new TreeMap<>(utils.comparators.packageComparator()); /** * Map of indirect modules (transitive closure) and their exported packages. */ private final Map> indirectPackages - = new TreeMap<>(comparators.makeModuleComparator()); + = new TreeMap<>(comparators.moduleComparator()); /** * Map of indirect modules (transitive closure) and their open packages. */ private final Map> indirectOpenPackages - = new TreeMap<>(comparators.makeModuleComparator()); + = new TreeMap<>(comparators.moduleComparator()); /** * Set of services used by the module. */ private final SortedSet uses - = new TreeSet<>(comparators.makeAllClassesComparator()); + = new TreeSet<>(comparators.allClassesComparator()); /** * Map of services used by the module and specified using @uses javadoc tag, and description. */ private final Map usesTrees - = new TreeMap<>(comparators.makeAllClassesComparator()); + = new TreeMap<>(comparators.allClassesComparator()); /** * Map of services provided by this module, and set of its implementations. */ private final Map> provides - = new TreeMap<>(comparators.makeAllClassesComparator()); + = new TreeMap<>(comparators.allClassesComparator()); /** * Map of services provided by the module and specified using @provides javadoc tag, and * description. */ private final Map providesTrees - = new TreeMap<>(comparators.makeAllClassesComparator()); + = new TreeMap<>(comparators.allClassesComparator()); private final BodyContents bodyContents = new BodyContents(); @@ -186,7 +186,7 @@ protected void buildModuleDoc() throws DocletException { addModuleFooter(); printDocument(content); - var docFilesHandler = configuration.getWriterFactory().getDocFilesHandler(mdle); + var docFilesHandler = configuration.getWriterFactory().newDocFilesHandler(mdle); docFilesHandler.copyDocFiles(); } @@ -348,7 +348,7 @@ public void computeModulesData() { // Include package if in details mode, or exported to all (i.e. targetModules == null) if (moduleMode == ModuleMode.ALL || targetMdles == null) { PackageEntry packageEntry = packages.computeIfAbsent(p, pkg -> new PackageEntry()); - SortedSet mdleList = new TreeSet<>(utils.comparators.makeModuleComparator()); + SortedSet mdleList = new TreeSet<>(utils.comparators.moduleComparator()); if (targetMdles != null) { mdleList.addAll(targetMdles); } @@ -366,7 +366,7 @@ public void computeModulesData() { // Include package if in details mode, or opened to all (i.e. targetModules == null) if (moduleMode == ModuleMode.ALL || targetMdles == null) { PackageEntry packageEntry = packages.computeIfAbsent(p, pkg -> new PackageEntry()); - SortedSet mdleList = new TreeSet<>(utils.comparators.makeModuleComparator()); + SortedSet mdleList = new TreeSet<>(utils.comparators.moduleComparator()); if (targetMdles != null) { mdleList.addAll(targetMdles); } @@ -378,7 +378,7 @@ public void computeModulesData() { // Get all the exported and opened packages, for the transitive closure of the module, to be displayed in // the indirect packages tables. dependentModules.forEach((module, mod) -> { - SortedSet exportedPackages = new TreeSet<>(utils.comparators.makePackageComparator()); + SortedSet exportedPackages = new TreeSet<>(utils.comparators.packageComparator()); ElementFilter.exportsIn(module.getDirectives()).forEach(directive -> { PackageElement pkg = directive.getPackage(); if (shouldDocument(pkg)) { @@ -393,7 +393,7 @@ public void computeModulesData() { if (!exportedPackages.isEmpty()) { indirectPackages.put(module, exportedPackages); } - SortedSet openPackages = new TreeSet<>(utils.comparators.makePackageComparator()); + SortedSet openPackages = new TreeSet<>(utils.comparators.packageComparator()); if (module.isOpen()) { openPackages.addAll(utils.getModulePackageMap().getOrDefault(module, Set.of())); } else { @@ -425,7 +425,7 @@ public void computeModulesData() { TypeElement u = directive.getService(); if (shouldDocument(u)) { List implList = directive.getImplementations(); - SortedSet implSet = new TreeSet<>(utils.comparators.makeAllClassesComparator()); + SortedSet implSet = new TreeSet<>(utils.comparators.allClassesComparator()); implSet.addAll(implList); provides.put(u, implSet); } @@ -609,7 +609,7 @@ protected void addPackagesSummary(Content summariesList) { /** * Add the package summary for the module. * - * @param li + * @param li the tree to which the summary will be added */ public void addPackageSummary(HtmlTree li) { var table = new Table(HtmlStyle.summaryTable) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java index 3bab83a2d4b..e2a4e7fb0eb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java @@ -36,20 +36,27 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; /** * Writes nested class documentation in HTML format. */ public class NestedClassWriter extends AbstractMemberWriter { - public NestedClassWriter(SubWriterHolderWriter writer, TypeElement typeElement) { - super(writer, typeElement); + public NestedClassWriter(ClassWriter writer) { + super(writer, VisibleMemberTable.Kind.NESTED_CLASSES); } + // used in ClassUseWriter and SummaryUseWriter public NestedClassWriter(SubWriterHolderWriter writer) { super(writer); } + @Override + public void buildDetails(Content target) { + throw new UnsupportedOperationException(); + } + @Override public Content getMemberSummaryHeader(TypeElement typeElement, Content content) { @@ -60,7 +67,7 @@ public Content getMemberSummaryHeader(TypeElement typeElement, } @Override - public void addSummary(Content summariesList, Content content) { + public void buildSummary(Content summariesList, Content content) { writer.addSummary(HtmlStyle.nestedClassSummary, HtmlIds.NESTED_CLASS_SUMMARY, summariesList, content); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java index 1f5b4e6fb40..cfc61034005 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java @@ -79,7 +79,7 @@ public PackageUseWriter(HtmlConfiguration configuration, Set usedClasses = usingPackageToUsedClasses .get(utils.getPackageName(usingPackage)); if (usedClasses == null) { - usedClasses = new TreeSet<>(comparators.makeGeneralPurposeComparator()); + usedClasses = new TreeSet<>(comparators.generalPurposeComparator()); usingPackageToUsedClasses.put(utils.getPackageName(usingPackage), usedClasses); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java index ef0ae1ea065..038f4c5292d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java @@ -123,7 +123,7 @@ protected void buildPackageDoc() throws DocletException { printDocument(content); var docFilesHandler = configuration .getWriterFactory() - .getDocFilesHandler(packageElement); + .newDocFilesHandler(packageElement); docFilesHandler.copyDocFiles(); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java index 2a2ecdc23be..b650a54f4d6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java @@ -56,10 +56,11 @@ public class PropertyWriter extends AbstractMemberWriter { private ExecutableElement currentProperty; public PropertyWriter(ClassWriter writer) { - super(writer, writer.typeElement); + super(writer, writer.typeElement, VisibleMemberTable.Kind.PROPERTIES); } - public void build(Content target) { + @Override + public void buildDetails(Content target) { buildPropertyDoc(target); } @@ -165,7 +166,7 @@ public Content getMemberSummaryHeader(TypeElement typeElement, Content content) } @Override - public void addSummary(Content summariesList, Content content) { + public void buildSummary(Content summariesList, Content content) { writer.addSummary(HtmlStyle.propertySummary, HtmlIds.PROPERTY_SUMMARY, summariesList, content); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java index 1a5d328fd9f..f1189c034ec 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java @@ -109,7 +109,7 @@ public SerializedFormWriter(HtmlConfiguration configuration) { * @throws DocletException if there is a problem while building the documentation */ void build() throws DocletException { - SortedSet rootclasses = new TreeSet<>(utils.comparators.makeGeneralPurposeComparator()); + SortedSet rootclasses = new TreeSet<>(utils.comparators.generalPurposeComparator()); rootclasses.addAll(configuration.getIncludedTypeElements()); if (!serialClassFoundToDocument(rootclasses)) { //Nothing to document. @@ -443,7 +443,7 @@ protected void buildSerialFieldTagsInfo(Content target) { // ObjectStreamFields. Print a member for each serialField tag. // (There should be one serialField tag per ObjectStreamField // element.) - SortedSet tags = new TreeSet<>(utils.comparators.makeSerialFieldTreeComparator()); + SortedSet tags = new TreeSet<>(utils.comparators.serialFieldTreeComparator()); // sort the elements tags.addAll(utils.getSerialFieldTrees(field)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java index d2e4fff02a0..6cb71c49851 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java @@ -37,6 +37,7 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.toolkit.PropertyUtils; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; /** @@ -65,6 +66,10 @@ public SubWriterHolderWriter(HtmlConfiguration configuration, DocPath filename, super(configuration, filename, generating); } + public PropertyUtils.PropertyHelper getPropertyHelper() { + throw new UnsupportedOperationException(); + } + /** * Add the summary header. * @@ -294,15 +299,6 @@ public Content getMemberSummary(Content memberContent) { return HtmlTree.SECTION(HtmlStyle.summary, memberContent); } - /** - * {@return the member details} - * - * @param content the content used to generate the member details - */ - public Content getMemberDetailsContent(Content content) { - return HtmlTree.SECTION(HtmlStyle.details, content); - } - /** * Get the member content * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java index af960414658..49b6f4b3b0a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java @@ -352,6 +352,7 @@ public void addRow(T item, List contents) { * * @return true if the table has no rows */ + @Override public boolean isEmpty() { return bodyRows.isEmpty(); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactory.java index c2602cfd23d..5e6f1f4f9d2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactory.java @@ -37,97 +37,75 @@ /** * The factory that returns HTML writers. */ -// TODO: be more consistent about using this factory public class WriterFactory { private final HtmlConfiguration configuration; + public WriterFactory(HtmlConfiguration configuration) { this.configuration = configuration; } - public ConstantsSummaryWriter getConstantsSummaryWriter() { + /** + * {@return a new {@link ConstantsSummaryWriter}} + */ + public ConstantsSummaryWriter newConstantsSummaryWriter() { return new ConstantsSummaryWriter(configuration); } - public PackageWriter getPackageSummaryWriter(PackageElement packageElement) { + /** + * {@return a new {@link PackageWriter}} + */ + public PackageWriter newPackageWriter(PackageElement packageElement) { return new PackageWriter(configuration, packageElement); } - public ModuleWriter getModuleSummaryWriter(ModuleElement mdle) { + /** + * {@return a new {@link ModuleWriter}} + */ + public ModuleWriter newModuleWriter(ModuleElement mdle) { return new ModuleWriter(configuration, mdle); } - public ClassWriter getClassWriter(TypeElement typeElement, ClassTree classTree) { + /** + * {@return a new {@link ClassWriter}} + */ + public ClassWriter newClassWriter(TypeElement typeElement, ClassTree classTree) { return new ClassWriter(configuration, typeElement, classTree); } - - public AnnotationTypeMemberWriter getAnnotationTypeMemberWriter( - ClassWriter classWriter) { - TypeElement te = classWriter.getTypeElement(); - return new AnnotationTypeMemberWriter(classWriter, te, AnnotationTypeMemberWriter.Kind.ANY); - } - - public AnnotationTypeMemberWriter getAnnotationTypeOptionalMemberWriter( - ClassWriter classWriter) { - TypeElement te = classWriter.getTypeElement(); - return new AnnotationTypeMemberWriter(classWriter, te, AnnotationTypeMemberWriter.Kind.OPTIONAL); - } - - public AnnotationTypeMemberWriter getAnnotationTypeRequiredMemberWriter( - ClassWriter classWriter) { - TypeElement te = classWriter.getTypeElement(); - return new AnnotationTypeMemberWriter(classWriter, te, AnnotationTypeMemberWriter.Kind.REQUIRED); - } - - public EnumConstantWriter getEnumConstantWriter(ClassWriter classWriter) { - return new EnumConstantWriter(classWriter); - } - - public FieldWriter getFieldWriter(ClassWriter classWriter) { - return new FieldWriter(classWriter); - } - - public PropertyWriter getPropertyWriter(ClassWriter classWriter) { - return new PropertyWriter(classWriter); - } - - public MethodWriter getMethodWriter(ClassWriter classWriter) { - return new MethodWriter(classWriter); - } - - public ConstructorWriter getConstructorWriter(ClassWriter classWriter) { - return new ConstructorWriter(classWriter); - } - - public AbstractMemberWriter getMemberSummaryWriter(ClassWriter classWriter, - VisibleMemberTable.Kind memberType) { - switch (memberType) { - case CONSTRUCTORS: - return getConstructorWriter(classWriter); - case ENUM_CONSTANTS: - return getEnumConstantWriter(classWriter); - case ANNOTATION_TYPE_MEMBER_OPTIONAL: - return getAnnotationTypeOptionalMemberWriter(classWriter); - case ANNOTATION_TYPE_MEMBER_REQUIRED: - return getAnnotationTypeRequiredMemberWriter(classWriter); - case FIELDS: - return getFieldWriter(classWriter); - case PROPERTIES: - return getPropertyWriter(classWriter); - case NESTED_CLASSES: - return new NestedClassWriter(classWriter, classWriter.getTypeElement()); - case METHODS: - return getMethodWriter(classWriter); - default: - return null; - } - } - - public SerializedFormWriter getSerializedFormWriter() { + /** + * {@return a new {@link SerializedFormWriter}} + */ + public SerializedFormWriter newSerializedFormWriter() { return new SerializedFormWriter(configuration); } - public DocFilesHandler getDocFilesHandler(Element element) { + /** + * Returns a new member writer for the members of a given class and given kind. + * + * @param classWriter the writer for the enclosing class + * @param kind the kind + * + * @return the writer + */ + public AbstractMemberWriter newMemberWriter(ClassWriter classWriter, + VisibleMemberTable.Kind kind) { + return switch (kind) { + case ANNOTATION_TYPE_MEMBER, + ANNOTATION_TYPE_MEMBER_OPTIONAL, + ANNOTATION_TYPE_MEMBER_REQUIRED -> new AnnotationTypeMemberWriter(classWriter, kind); + case CONSTRUCTORS -> new ConstructorWriter(classWriter); + case ENUM_CONSTANTS -> new EnumConstantWriter(classWriter); + case FIELDS -> new FieldWriter(classWriter); + case NESTED_CLASSES -> new NestedClassWriter(classWriter); + case METHODS -> new MethodWriter(classWriter); + case PROPERTIES -> new PropertyWriter(classWriter); + }; + } + + /** + * {@return a new {@link DocFilesHandler}} + */ + public DocFilesHandler newDocFilesHandler(Element element) { return new DocFilesHandler(configuration, element); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java index 0153704175e..6b3d8df23f2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java @@ -228,7 +228,7 @@ protected abstract void generateClassFiles(SortedSet arr, ClassTree protected void generateClassFiles(ClassTree classTree) throws DocletException { - SortedSet classes = new TreeSet<>(utils.comparators.makeGeneralPurposeComparator()); + SortedSet classes = new TreeSet<>(utils.comparators.generalPurposeComparator()); // handle classes specified as files on the command line for (PackageElement pkg : configuration.typeElementCatalog.packages()) { @@ -236,7 +236,7 @@ protected void generateClassFiles(ClassTree classTree) } // handle classes specified in modules and packages on the command line - SortedSet packages = new TreeSet<>(utils.comparators.makePackageComparator()); + SortedSet packages = new TreeSet<>(utils.comparators.packageComparator()); packages.addAll(configuration.getSpecifiedPackageElements()); configuration.modulePackages.values().stream().forEach(packages::addAll); for (PackageElement pkg : packages) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java index 029e743a504..f3749677b9e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java @@ -286,15 +286,15 @@ public Set getIncludedTypeElements() { private void initModules() { Comparators comparators = utils.comparators; // Build the modules structure used by the doclet - modules = new TreeSet<>(comparators.makeModuleComparator()); + modules = new TreeSet<>(comparators.moduleComparator()); modules.addAll(getSpecifiedModuleElements()); - modulePackages = new TreeMap<>(comparators.makeModuleComparator()); + modulePackages = new TreeMap<>(comparators.moduleComparator()); for (PackageElement p : packages) { ModuleElement mdle = docEnv.getElementUtils().getModuleOf(p); if (mdle != null && !mdle.isUnnamed()) { Set s = modulePackages - .computeIfAbsent(mdle, m -> new TreeSet<>(comparators.makePackageComparator())); + .computeIfAbsent(mdle, m -> new TreeSet<>(comparators.packageComparator())); s.add(p); } } @@ -303,7 +303,7 @@ private void initModules() { ModuleElement mdle = docEnv.getElementUtils().getModuleOf(p); if (mdle != null && !mdle.isUnnamed()) { Set s = modulePackages - .computeIfAbsent(mdle, m -> new TreeSet<>(comparators.makePackageComparator())); + .computeIfAbsent(mdle, m -> new TreeSet<>(comparators.packageComparator())); s.add(p); } } @@ -319,7 +319,7 @@ private void initModules() { } private void initPackages() { - packages = new TreeSet<>(utils.comparators.makePackageComparator()); + packages = new TreeSet<>(utils.comparators.packageComparator()); // add all the included packages packages.addAll(includedPackageElements); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java index c1c9d0bb6b7..0aa425e54dc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java @@ -40,7 +40,6 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; @@ -56,11 +55,8 @@ import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.TypeTag; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; -import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Options; @@ -280,8 +276,8 @@ static class NewSerializedForm { NewSerializedForm(Utils utils, Elements elements, TypeElement te) { this.utils = utils; this.elements = elements; - methods = new TreeSet<>(utils.comparators.makeGeneralPurposeComparator()); - fields = new TreeSet<>(utils.comparators.makeGeneralPurposeComparator()); + methods = new TreeSet<>(utils.comparators.generalPurposeComparator()); + fields = new TreeSet<>(utils.comparators.generalPurposeComparator()); if (utils.isExternalizable(te)) { /* look up required public accessible methods, * writeExternal and readExternal. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java index ee58170e2fc..7cde2a99453 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java @@ -185,7 +185,7 @@ public ClassTree(BaseConfiguration configuration) { Messages messages = configuration.getMessages(); messages.notice("doclet.Building_Tree"); - Comparator comparator = utils.comparators.makeClassUseComparator(); + Comparator comparator = utils.comparators.classUseComparator(); hierarchies = new EnumMap<>(HierarchyKind.class); for (var hk : HierarchyKind.values()) { @@ -206,7 +206,7 @@ public ClassTree(SortedSet classesSet, BaseConfiguration configurat this.configuration = configuration; this.utils = configuration.utils; - Comparator comparator = utils.comparators.makeClassUseComparator(); + Comparator comparator = utils.comparators.classUseComparator(); hierarchies = new EnumMap<>(HierarchyKind.class); for (var hk : HierarchyKind.values()) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java index a7a5416544b..3f16e3458fb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java @@ -199,7 +199,7 @@ public ClassUseMapper(BaseConfiguration configuration, ClassTree classTree) { utils = configuration.utils; comparators = utils.comparators; this.classTree = classTree; - classToPackage = new TreeMap<>(comparators.makeClassUseComparator()); + classToPackage = new TreeMap<>(comparators.classUseComparator()); // Map subclassing, subinterfacing implementing, ... for (TypeElement te : classTree.classes().roots()) { subclasses(te); @@ -285,7 +285,7 @@ protected Void defaultAction(TypeMirror e, ExecutableElement p) { private Collection subclasses(TypeElement te) { Collection ret = classToSubclass.get(te); if (ret == null) { - ret = new TreeSet<>(comparators.makeClassUseComparator()); + ret = new TreeSet<>(comparators.classUseComparator()); Set subs = classTree.subClasses(te); if (subs != null) { ret.addAll(subs); @@ -304,7 +304,7 @@ private Collection subclasses(TypeElement te) { private Collection subinterfaces(TypeElement te) { Collection ret = classToSubinterface.get(te); if (ret == null) { - ret = new TreeSet<>(comparators.makeClassUseComparator()); + ret = new TreeSet<>(comparators.classUseComparator()); Set subs = classTree.subInterfaces(te); if (subs != null) { ret.addAll(subs); @@ -325,7 +325,7 @@ private Collection subinterfaces(TypeElement te) { private Collection implementingClasses(TypeElement te) { Collection ret = classToImplementingClass.get(te); if (ret == null) { - ret = new TreeSet<>(comparators.makeClassUseComparator()); + ret = new TreeSet<>(comparators.classUseComparator()); Set impl = classTree.implementingClasses(te); if (impl != null) { ret.addAll(impl); @@ -346,7 +346,7 @@ private Collection implementingClasses(TypeElement te) { */ private void mapExecutable(ExecutableElement ee) { final boolean isConstructor = utils.isConstructor(ee); - Set classArgs = new TreeSet<>(comparators.makeTypeMirrorClassUseComparator()); + Set classArgs = new TreeSet<>(comparators.typeMirrorClassUseComparator()); for (VariableElement param : ee.getParameters()) { TypeMirror pType = param.asType(); // primitives don't get mapped and type variables are mapped elsewhere @@ -425,7 +425,7 @@ private List refList(Map> map, TypeElement element) private Set packageSet(TypeElement te) { Set pkgSet = classToPackage.get(te); if (pkgSet == null) { - pkgSet = new TreeSet<>(comparators.makeClassUseComparator()); + pkgSet = new TreeSet<>(comparators.classUseComparator()); classToPackage.put(te, pkgSet); } return pkgSet; @@ -434,7 +434,7 @@ private Set packageSet(TypeElement te) { private Set classSet(TypeElement te) { Set clsSet = classToClass.get(te); if (clsSet == null) { - clsSet = new TreeSet<>(comparators.makeClassUseComparator()); + clsSet = new TreeSet<>(comparators.classUseComparator()); classToClass.put(te, clsSet); } return clsSet; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java index c715dda9e31..f1429922742 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java @@ -55,10 +55,11 @@ public class Comparators { private Comparator moduleComparator = null; /** - * Comparator for ModuleElements, simply compares the fully qualified names - * @return a Comparator + * Returns a comparator for module elements, that simply compares the fully qualified names + * + * @return the comparator */ - public Comparator makeModuleComparator() { + public Comparator moduleComparator() { if (moduleComparator == null) { moduleComparator = new ElementComparator() { @Override @@ -73,13 +74,13 @@ public int compare(Element mod1, Element mod2) { private Comparator allClassesComparator = null; /** - * Returns a Comparator for all classes, compares the simple names of - * TypeElement, if equal then the fully qualified names, and if equal again + * Returns a comparator for all classes, that compares the simple names of + * the type element, if equal then the fully qualified names, and if equal again * the names of the enclosing modules. * - * @return Comparator + * @return the comparator */ - public Comparator makeAllClassesComparator() { + public Comparator allClassesComparator() { if (allClassesComparator == null) { allClassesComparator = new ElementComparator() { @Override @@ -99,12 +100,12 @@ public int compare(Element e1, Element e2) { private Comparator packageComparator = null; /** - * Returns a Comparator for packages, by comparing the fully qualified names, + * Returns a comparator for packages, by comparing the fully qualified names, * and if those are equal the names of the enclosing modules. * - * @return a Comparator + * @return the comparator */ - public Comparator makePackageComparator() { + public Comparator packageComparator() { if (packageComparator == null) { packageComparator = new ElementComparator() { @Override @@ -122,13 +123,13 @@ public int compare(Element pkg1, Element pkg2) { private Comparator summaryComparator = null; /** - * Returns a Comparator for items listed on summary list pages + * Returns a comparator for items listed on summary list pages * (like deprecated or preview summary pages), by comparing the * fully qualified names, and if those are equal the names of the enclosing modules. * - * @return a Comparator + * @return the comparator */ - public Comparator makeSummaryComparator() { + public Comparator summaryComparator() { if (summaryComparator == null) { summaryComparator = new ElementComparator() { @Override @@ -152,10 +153,11 @@ public int compare(Element e1, Element e2) { private Comparator serialFieldTreeComparator = null; /** - * Returns a Comparator for SerialFieldTree. - * @return a Comparator + * Returns a comparator for {@link SerialFieldTree}s. + * + * @return the comparator */ - public Comparator makeSerialFieldTreeComparator() { + public Comparator serialFieldTreeComparator() { if (serialFieldTreeComparator == null) { serialFieldTreeComparator = (SerialFieldTree o1, SerialFieldTree o2) -> { String s1 = o1.getName().toString(); @@ -168,22 +170,25 @@ public Comparator makeSerialFieldTreeComparator() { /** * Returns a general purpose comparator. - * @return a Comparator + * + * @return the comparator */ - public Comparator makeGeneralPurposeComparator() { - return makeClassUseComparator(); + public Comparator generalPurposeComparator() { + return classUseComparator(); } private Comparator overrideUseComparator = null; /** - * Returns a Comparator for overrides and implements, + * Returns a comparator for overrides and implements, * used primarily on methods, compares the name first, * then compares the simple names of the enclosing - * TypeElement and the fully qualified name of the enclosing TypeElement. - * @return a Comparator + * type element and the fully qualified name of the enclosing + * type element. + * + * @return the comparator */ - public Comparator makeOverrideUseComparator() { + public Comparator overrideUseComparator() { if (overrideUseComparator == null) { overrideUseComparator = new ElementComparator() { @Override @@ -219,13 +224,14 @@ public int compare(Element o1, Element o2) { * otherwise: * 1. compare the ElementKind ex: Module, Package, Interface etc. * 2a. if equal and if the type is of ExecutableElement(Constructor, Methods), - * a case insensitive comparison of parameter the type signatures - * 2b. if equal, case sensitive comparison of the type signatures + * a case-insensitive comparison of parameter the type signatures + * 2b. if equal, case-sensitive comparison of the type signatures * 3. if equal, compare the FQNs of the entities * 4. finally, if equal, compare the names of the enclosing modules + * * @return an element comparator for index file use */ - public Comparator makeIndexElementComparator() { + public Comparator indexElementComparator() { if (indexUseComparator == null) { indexUseComparator = new ElementComparator() { /** @@ -239,7 +245,7 @@ public Comparator makeIndexElementComparator() { @Override public int compare(Element e1, Element e2) { // first, compare names as appropriate - int result = utils.compareStrings(getIndexElementKey(e1), getIndexElementKey(e2)); + int result = utils.compareStrings(indexElementKey(e1), indexElementKey(e2)); if (result != 0) { return result; } @@ -272,7 +278,7 @@ public int compare(Element e1, Element e2) { * * @param element an element */ - public String getIndexElementKey(Element element) { + public String indexElementKey(Element element) { return switch (element.getKind()) { case MODULE, PACKAGE -> utils.getFullyQualifiedName(element); default -> utils.getSimpleName(element); @@ -286,7 +292,7 @@ public String getIndexElementKey(Element element) { * * @return the comparator */ - public Comparator makeTypeMirrorClassUseComparator() { + public Comparator typeMirrorClassUseComparator() { if (typeMirrorClassUseComparator == null) { typeMirrorClassUseComparator = (TypeMirror type1, TypeMirror type2) -> { String s1 = utils.getQualifiedTypeName(type1); @@ -305,7 +311,7 @@ public Comparator makeTypeMirrorClassUseComparator() { * * @return the comparator */ - public Comparator makeTypeMirrorIndexUseComparator() { + public Comparator typeMirrorIndexUseComparator() { if (typeMirrorIndexUseComparator == null) { typeMirrorIndexUseComparator = (TypeMirror t1, TypeMirror t2) -> { int result = utils.compareStrings(utils.getTypeName(t1, false), utils.getTypeName(t2, false)); @@ -326,9 +332,10 @@ public Comparator makeTypeMirrorIndexUseComparator() { * 3. then parameter types if applicable * 4. the element kinds ie. package, class, interface etc. * 5. finally the name of the enclosing modules + * * @return a comparator to sort classes and members for class use */ - public Comparator makeClassUseComparator() { + public Comparator classUseComparator() { if (classUseComparator == null) { classUseComparator = new ElementComparator() { /** @@ -366,7 +373,7 @@ public int compare(Element e1, Element e2) { /** * A general purpose comparator to sort Element entities, basically provides the building blocks - * for creating specific comparators for an use-case. + * for creating specific comparators for each use-case. */ private abstract class ElementComparator implements Comparator { public ElementComparator() { } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java index 7842808c044..f0cb94200df 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java @@ -326,7 +326,7 @@ String regExpGroupName(String elementName) { */ SortedSet getPkgList(Map> map, String groupname) { - return map.computeIfAbsent(groupname, g -> new TreeSet<>(configuration.utils.comparators.makePackageComparator())); + return map.computeIfAbsent(groupname, g -> new TreeSet<>(configuration.utils.comparators.packageComparator())); } /** @@ -338,7 +338,7 @@ SortedSet getPkgList(Map> map, */ SortedSet getModuleList(Map> map, String groupname) { - return map.computeIfAbsent(groupname, g -> new TreeSet<>(configuration.utils.comparators.makeModuleComparator())); + return map.computeIfAbsent(groupname, g -> new TreeSet<>(configuration.utils.comparators.moduleComparator())); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java index e3c88641b3b..3bb212f1dac 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java @@ -315,7 +315,7 @@ private static Character keyCharacter(String s) { * @return a comparator for class element items */ private Comparator makeClassComparator() { - return Comparator.comparing(IndexItem::getElement, utils.comparators.makeAllClassesComparator()); + return Comparator.comparing(IndexItem::getElement, utils.comparators.allClassesComparator()); } /** @@ -331,7 +331,7 @@ private Comparator makeIndexComparator() { // In order to produce consistent results, it is important that the base comparator // uses the same primary sort keys as both the element and search tag comparators // (see JDK-8311264). - Comparator elementComparator = utils.comparators.makeIndexElementComparator(); + Comparator elementComparator = utils.comparators.indexElementComparator(); Comparator baseComparator = (ii1, ii2) -> utils.compareStrings(getIndexItemKey(ii1), getIndexItemKey(ii2)); Comparator searchTagComparator = @@ -374,7 +374,7 @@ private String getIndexItemKey(IndexItem ii) { // For element items return the key used by the element comparator; // for search tag items return the item's label. return ii.isElementItem() - ? utils.comparators.getIndexElementKey(ii.getElement()) + ? utils.comparators.indexElementKey(ii.getElement()) : ii.getLabel(); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java index ac21c9ae7fc..5125656c821 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java @@ -62,7 +62,7 @@ public enum SummaryElementKind { CONSTRUCTOR, ENUM_CONSTANT, ANNOTATION_TYPE_MEMBER // no ElementKind mapping - }; + } /** * Constructor. @@ -180,10 +180,10 @@ private void composeSummaryList(SortedSet sset, List } /** - * Return the list of summary elements of a given type. + * Return the set of summary elements of a given type. * * @param kind the SummaryElementKind - * @return + * @return the set */ public SortedSet getSet(SummaryElementKind kind) { return summaryMap.get(kind); @@ -211,6 +211,6 @@ protected void handleElement(Element e) {} * @return a summary set */ protected final SortedSet createSummarySet() { - return new TreeSet<>(utils.comparators.makeSummaryComparator()); + return new TreeSet<>(utils.comparators.summaryComparator()); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/TypeElementCatalog.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/TypeElementCatalog.java index 23791578a07..ca4ad023504 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/TypeElementCatalog.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/TypeElementCatalog.java @@ -79,7 +79,7 @@ public TypeElementCatalog(Iterable typeElements, BaseConfiguration public TypeElementCatalog(BaseConfiguration config) { this.configuration = config; this.utils = config.utils; - comparator = utils.comparators.makeGeneralPurposeComparator(); + comparator = utils.comparators.generalPurposeComparator(); allClasses = new HashMap<>(); packageSet = new TreeSet<>(comparator); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 1086bcf68d5..37e554b6d17 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -660,7 +660,7 @@ public OverrideInfo overriddenMethod(ExecutableElement method) { } public SortedSet getTypeElementsAsSortedSet(Iterable typeElements) { - SortedSet set = new TreeSet<>(comparators.makeGeneralPurposeComparator()); + SortedSet set = new TreeSet<>(comparators.generalPurposeComparator()); typeElements.forEach(set::add); return set; } @@ -1317,7 +1317,7 @@ public boolean isSimpleOverride(ExecutableElement m) { public SortedSet filterOutPrivateClasses(Iterable classlist, boolean javafx) { SortedSet filteredOutClasses = - new TreeSet<>(comparators.makeGeneralPurposeComparator()); + new TreeSet<>(comparators.generalPurposeComparator()); if (!javafx) { for (TypeElement te : classlist) { if (!hasHiddenTag(te)) { @@ -1604,7 +1604,7 @@ public Map> getModulePackageMap() { } public Map getDependentModules(ModuleElement mdle) { - Map result = new TreeMap<>(comparators.makeModuleComparator()); + Map result = new TreeMap<>(comparators.moduleComparator()); Deque queue = new ArrayDeque<>(); // get all the requires for the element in question for (RequiresDirective rd : ElementFilter.requiresIn(mdle.getDirectives())) { @@ -1678,7 +1678,7 @@ public List getEnumConstants(TypeElement te) { * @return the interfaces */ public SortedSet getAllClassesUnfiltered(PackageElement pkg) { - SortedSet set = new TreeSet<>(comparators.makeGeneralPurposeComparator()); + SortedSet set = new TreeSet<>(comparators.generalPurposeComparator()); set.addAll(getItems(pkg, true, this::isTypeElement, TypeElement.class)); return set; } @@ -1694,7 +1694,7 @@ public SortedSet getAllClassesUnfiltered(PackageElement pkg) { public SortedSet getAllClasses(PackageElement pkg) { return cachedClasses.computeIfAbsent(pkg, p_ -> { List clist = getItems(pkg, false, this::isTypeElement, TypeElement.class); - SortedSetoset = new TreeSet<>(comparators.makeGeneralPurposeComparator()); + SortedSetoset = new TreeSet<>(comparators.generalPurposeComparator()); oset.addAll(clist); return oset; }); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java index 3ec016ace47..70490693bf4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java @@ -56,7 +56,6 @@ import java.util.Objects; import java.util.Set; import java.util.function.Predicate; -import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; @@ -351,7 +350,7 @@ public Set getVisibleTypeElements() { // ... and finally the sorted superinterfaces. allSuperinterfaces.stream() .map(vmt -> vmt.te) - .sorted(utils.comparators.makeGeneralPurposeComparator()) + .sorted(utils.comparators.generalPurposeComparator()) .forEach(result::add); return result; diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index feae8c7af4f..3cd34df5c4f 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -98,8 +98,6 @@ runtime/os/TestTracePageSizes.java#compiler-options 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#G1 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 -runtime/os/TestTrimNative.java#trimNative 8312525 linux-all -runtime/os/TestTrimNative.java#trimNativeLowInterval 8312525 linux-all runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 runtime/CompressedOops/CompressedClassPointers.java 8305765 generic-all runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all diff --git a/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java new file mode 100644 index 00000000000..8e2db5067d8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8304954 + * @summary Code cache reservation should gracefully downgrade to using smaller pages if the code cache size is too small to host the requested page size. + * @requires os.family == "linux" + * @requires vm.gc != "Z" + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseLargePages -XX:LargePageSizeInBytes=1g compiler.codecache.CheckLargePages + */ + +package compiler.codecache; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; + +import java.util.Arrays; +import java.util.List; + +public class CheckLargePages { + private final static WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + public static void main(String[] args) throws Exception { + final boolean largePages = WHITE_BOX.getBooleanVMFlag("UseLargePages"); + final long largePageSize = WHITE_BOX.getVMLargePageSize(); + if (largePages && (largePageSize == 1024 * 1024 * 1024)) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseLargePages", + "-XX:+SegmentedCodeCache", + "-XX:InitialCodeCacheSize=2g", + "-XX:ReservedCodeCacheSize=2g", + "-XX:LargePageSizeInBytes=1g", + "-Xlog:pagesize=info", + "-version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldMatch("Code cache size too small for \\S* pages\\. Reverting to smaller page size \\((\\S*)\\)\\."); + out.shouldHaveExitValue(0); + // Parse page sizes to find next biggest page + String sizes = out.firstMatch("Usable page sizes:(.*)", 1); + List sizeList = Arrays.stream(sizes.trim().split("\\s*,\\s*")).map(CheckLargePages::parseMemoryString).sorted().toList(); + final int smallerPageSizeIndex = sizeList.indexOf(largePageSize) - 1; + Asserts.assertGreaterThanOrEqual(smallerPageSizeIndex, 0); + final long smallerPageSize = sizeList.get(smallerPageSizeIndex); + // Retrieve reverted page size from code cache warning + String revertedSizeString = out.firstMatch("Code cache size too small for (\\S*) pages. Reverting to smaller page size \\((\\S*)\\)\\.", 2); + Asserts.assertEquals(parseMemoryString(revertedSizeString), smallerPageSize); + } else { + System.out.println("1GB large pages not supported: UseLargePages=" + largePages + + (largePages ? ", largePageSize=" + largePageSize : "") + ". Skipping"); + } + } + + public static long parseMemoryString(String value) { + value = value.toUpperCase(); + long multiplier = 1; + if (value.endsWith("B")) { + multiplier = 1; + } else if (value.endsWith("K")) { + multiplier = 1024; + } else if (value.endsWith("M")) { + multiplier = 1024 * 1024; + } else if (value.endsWith("G")) { + multiplier = 1024 * 1024 * 1024; + } else { + throw new IllegalArgumentException("Expected memory string '" + value + "'to end with either of: B, K, M, G"); + } + + long longValue = Long.parseUnsignedLong(value.substring(0, value.length() - 1)); + + return longValue * multiplier; + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java index aaee43e6882..26bc03c271b 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java @@ -24,20 +24,20 @@ /* * @test - * @requires os.arch=="aarch64" + * @requires os.arch=="aarch64" | os.arch=="riscv64" * @summary String::compareTo implementation uses different algorithms for * different string length. This test creates string with specified * size and longer string, which is same at beginning. * Expecting length delta to be returned. Test class takes 2 * parameters: , - * Input parameters for this test are set according to Aarch64 + * Input parameters for this test are set according to Aarch64/RISC-V * String::compareTo intrinsic implementation specifics. Aarch64 * implementation has 1, 4, 8 -bytes loops for length < 72 and - * 16, 32, 64 -characters loops for length >= 72. Code is also affected + * 16, 32, 64 -characters loops for length >= 72. Aarch64 Code is also affected * by SoftwarePrefetchHintDistance vm flag value. - * @run main/othervm -XX:SoftwarePrefetchHintDistance=192 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 23 24 25 71 72 73 88 90 192 193 208 209 - * @run main/othervm -XX:SoftwarePrefetchHintDistance=16 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 23 24 25 71 72 73 88 90 - * @run main/othervm -XX:SoftwarePrefetchHintDistance=-1 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 23 24 25 71 72 73 88 90 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:SoftwarePrefetchHintDistance=192 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 23 24 25 71 72 73 88 90 192 193 208 209 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:SoftwarePrefetchHintDistance=16 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 23 24 25 71 72 73 88 90 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:SoftwarePrefetchHintDistance=-1 compiler.intrinsics.string.TestStringCompareToDifferentLength 4 2 5 10 13 17 20 23 24 25 71 72 73 88 90 */ package compiler.intrinsics.string; diff --git a/test/hotspot/jtreg/runtime/os/TestTrimNative.java b/test/hotspot/jtreg/runtime/os/TestTrimNative.java index 50b6e561734..5fa87ea903f 100644 --- a/test/hotspot/jtreg/runtime/os/TestTrimNative.java +++ b/test/hotspot/jtreg/runtime/os/TestTrimNative.java @@ -34,6 +34,16 @@ * @run driver TestTrimNative trimNative */ +/* + * @test id=trimNativeStrict + * @requires (os.family=="linux") & !vm.musl + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/manual TestTrimNative trimNativeStrict + */ + /* * @test id=trimNativeHighInterval * @summary High interval trimming should not even kick in for short program runtimes @@ -56,6 +66,17 @@ * @run driver TestTrimNative trimNativeLowInterval */ +/* + * @test id=trimNativeLowIntervalStrict + * @summary Very low (sub-second) interval, nothing should explode (stricter test, manual mode) + * @requires (os.family=="linux") & !vm.musl + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/manual TestTrimNative trimNativeLowIntervalStrict + */ + /* * @test id=testOffByDefault * @summary Test that trimming is disabled by default @@ -161,9 +182,10 @@ private static void checkExpectedLogMessages(OutputAnalyzer output, boolean expe * @param output * @param minTrimsExpected min number of periodic trim lines expected in UL log * @param maxTrimsExpected min number of periodic trim lines expected in UL log + * @param strict: if true, expect RSS to go down; if false, just look for trims without looking at RSS. */ private static void parseOutputAndLookForNegativeTrim(OutputAnalyzer output, int minTrimsExpected, - int maxTrimsExpected) { + int maxTrimsExpected, boolean strict) { output.reportDiagnosticSummary(); List lines = output.asLines(); Pattern pat = Pattern.compile(".*\\[trimnative\\] Periodic Trim \\(\\d+\\): (\\d+)([BKMG])->(\\d+)([BKMG]).*"); @@ -188,7 +210,8 @@ private static void parseOutputAndLookForNegativeTrim(OutputAnalyzer output, int throw new RuntimeException("We found fewer (periodic) trim lines in UL log than expected (expected at least " + minTrimsExpected + ", found " + numTrimsFound + ")."); } - if (maxTrimsExpected > 0) { + System.out.println("Found " + numTrimsFound + " trims. Ok."); + if (strict && maxTrimsExpected > 0) { // This is very fuzzy. Test program malloced X bytes, then freed them again and trimmed. But the log line prints change in RSS. // Which, of course, is influenced by a lot of other factors. But we expect to see *some* reasonable reduction in RSS // due to trimming. @@ -203,6 +226,8 @@ private static void parseOutputAndLookForNegativeTrim(OutputAnalyzer output, int if (rssReductionTotal < expectedMinimalReduction) { throw new RuntimeException("We did not see the expected RSS reduction in the UL log. Expected (with fudge)" + " to see at least a combined reduction of " + expectedMinimalReduction + "."); + } else { + System.out.println("Found high enough RSS reduction from trims: " + rssReductionTotal); } } } @@ -238,8 +263,11 @@ public static void main(String[] args) throws Exception { throw new RuntimeException("Argument error"); } + boolean strictTesting = args[0].endsWith("Strict"); + switch (args[0]) { - case "trimNative": { + case "trimNative": + case "trimNativeStrict": { long trimInterval = 500; // twice per second long ms1 = System.currentTimeMillis(); OutputAnalyzer output = runTestWithOptions( @@ -253,7 +281,7 @@ public static void main(String[] args) throws Exception { long maxTrimsExpected = runtime_ms / trimInterval; long minTrimsExpected = maxTrimsExpected / 2; - parseOutputAndLookForNegativeTrim(output, (int) minTrimsExpected, (int) maxTrimsExpected); + parseOutputAndLookForNegativeTrim(output, (int) minTrimsExpected, (int) maxTrimsExpected, strictTesting); } break; case "trimNativeHighInterval": { @@ -263,16 +291,17 @@ public static void main(String[] args) throws Exception { ); checkExpectedLogMessages(output, true, Integer.MAX_VALUE); // We should not see any trims since the interval would prevent them - parseOutputAndLookForNegativeTrim(output, 0, 0); + parseOutputAndLookForNegativeTrim(output, 0, 0, strictTesting); } break; - case "trimNativeLowInterval": { + case "trimNativeLowInterval": + case "trimNativeLowIntervalStrict": { OutputAnalyzer output = runTestWithOptions( new String[] { "-XX:+UnlockExperimentalVMOptions", "-XX:TrimNativeHeapInterval=1" }, new String[] { TestTrimNative.Tester.class.getName(), "0" } ); checkExpectedLogMessages(output, true, 1); - parseOutputAndLookForNegativeTrim(output, 1, 3000); + parseOutputAndLookForNegativeTrim(output, 1, 3000, strictTesting); } break; case "testOffOnNonCompliantPlatforms": { @@ -281,7 +310,7 @@ public static void main(String[] args) throws Exception { new String[] { "-version" } ); checkExpectedLogMessages(output, false, 0); - parseOutputAndLookForNegativeTrim(output, 0, 0); + parseOutputAndLookForNegativeTrim(output, 0, 0, strictTesting); // The following output is expected to be printed with warning level, so it should not need -Xlog output.shouldContain("[warning][trimnative] Native heap trim is not supported on this platform"); } break; @@ -292,13 +321,13 @@ public static void main(String[] args) throws Exception { new String[] { "-version" } ); checkExpectedLogMessages(output, false, 0); - parseOutputAndLookForNegativeTrim(output, 0, 0); + parseOutputAndLookForNegativeTrim(output, 0, 0, strictTesting); } break; case "testOffByDefault": { OutputAnalyzer output = runTestWithOptions(null, new String[] { "-version" } ); checkExpectedLogMessages(output, false, 0); - parseOutputAndLookForNegativeTrim(output, 0, 0); + parseOutputAndLookForNegativeTrim(output, 0, 0, strictTesting); } break; default: diff --git a/test/jdk/java/lang/management/ThreadMXBean/Locks.java b/test/jdk/java/lang/management/ThreadMXBean/Locks.java index c3666b21f7e..a9c45887780 100644 --- a/test/jdk/java/lang/management/ThreadMXBean/Locks.java +++ b/test/jdk/java/lang/management/ThreadMXBean/Locks.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -43,8 +43,11 @@ public class Locks { - private static final Object OBJA = new Object(); - private static final Object OBJB = new Object(); + private static class ObjectA { } + private static class ObjectB { } + + private static final Object OBJA = new ObjectA(); + private static final Object OBJB = new ObjectB(); private static final EnhancedWaiter OBJC = new EnhancedWaiter(); private static final ThreadMXBean TM = ManagementFactory.getThreadMXBean(); private static final LockFreeLogger LOGGER = new LockFreeLogger(); @@ -65,6 +68,8 @@ private static void assertNoLock(Thread t) { TM.getThreadInfo(TM.getAllThreadIds(), true, true)) .filter(Objects::nonNull) .filter(i -> name.equals(i.getLockOwnerName())) + /* Carrier Thread can hold a lock on a VirtualThread, which we ignore: */ + .filter(i -> !i.getLockName().contains("java.lang.VirtualThread")) .findAny(); if (result.isPresent()) { throw new RuntimeException("Thread " + t.getName() + " is not " @@ -117,34 +122,34 @@ private static void assertThreadState(Thread t, Thread.State expectedState) { */ private static void checkBlockedObject(Thread t, Object lock, Thread owner) { long tid = t.getId(); - String result = TM.getThreadInfo(tid).getLockName(); + String lockName = TM.getThreadInfo(tid).getLockName(); final String expectedLock = (lock != null ? getLockName(lock) : null); Predicate p = (res) -> ((res != null && !res.equals(expectedLock)) || (res == null && expectedLock != null)); - if (p.test(result)) { + if (p.test(lockName)) { printStackTrace(t); int retryCount = 0; - while (p.test(result)) { + while (p.test(lockName)) { if (retryCount++ > 500) { printStackTrace(t); throw new RuntimeException("Thread " + t.getName() + " is blocked on " - + expectedLock + " but got " + result); + + expectedLock + " but got " + lockName); } goSleep(100); - result = TM.getThreadInfo(tid).getLockName(); + lockName = TM.getThreadInfo(tid).getLockName(); } } - result = TM.getThreadInfo(tid).getLockOwnerName(); - final String expectedOwner = (owner != null ? owner.getName() : null); + String lockOwnerName = TM.getThreadInfo(tid).getLockOwnerName(); + final String expectedOwnerName = (owner != null ? owner.getName() : null); - p = (res) -> ((res != null && !res.equals(expectedOwner)) - || (res == null && expectedOwner != null)); - if (p.test(result)) { + p = (res) -> ((res != null && !res.equals(expectedOwnerName)) + || (res == null && expectedOwnerName != null)); + if (p.test(lockOwnerName)) { printStackTrace(t); throw new RuntimeException("Owner of " + lock + " should be " - + expectedOwner + " but got " + result); + + expectedOwnerName + " but got " + lockOwnerName); } } @@ -342,14 +347,13 @@ Exception result() { public static void main(String args[]) throws Exception { try { Thread mainThread = Thread.currentThread(); - // Test uncontested case LockAThread t1; LockBThread t2; Phaser p = new Phaser(3); synchronized(OBJC) { - // Make sure the main thread is not holding any lock + // Make sure the main thread is not holding any lock (except possibly a VirtualThread) assertNoLock(mainThread); // Test deadlock case @@ -362,15 +366,22 @@ public static void main(String args[]) throws Exception { t2.start(); p.arriveAndAwaitAdvance(); // Phase 1 (blocking) + assertThreadState(t2, Thread.State.BLOCKED); - checkBlockedObject(t2, OBJC, mainThread); + if (!mainThread.isVirtual()) { + // ThreadInfo not available for Virtual Threads. + checkBlockedObject(t2, OBJC, mainThread); + } assertThreadState(t1, Thread.State.BLOCKED); checkBlockedObject(t1, OBJB, t2); - long[] expectedThreads = new long[3]; + long[] expectedThreads = new long[mainThread.isVirtual() ? 2: 3]; expectedThreads[0] = t1.getId(); // blocked on lockB expectedThreads[1] = t2.getId(); // owner of lockB blocking on lockC - expectedThreads[2] = mainThread.getId(); // owner of lockC + if (!mainThread.isVirtual()) { + // ThreadInfo not available for Virtual Threads. + expectedThreads[2] = mainThread.getId(); // owner of lockC + } findThreadsBlockedOn(OBJB, expectedThreads); } p.arriveAndAwaitAdvance(); // Phase 2 (blocking) @@ -400,6 +411,9 @@ private static ThreadInfo findOwnerInfo(ThreadInfo[] infos, String lock) throws Exception { ThreadInfo ownerInfo = null; for (ThreadInfo info : infos) { + if (info == null) { + continue; // Missing thread, e.g. completed. Ignore. + } String blockedLock = info.getLockName(); if (lock.equals(blockedLock)) { long threadId = info.getLockOwnerId(); @@ -421,12 +435,12 @@ private static void findThreadsBlockedOn(Object o, long[] expectedThreads) throws Exception { String lock = getLockName(o); // Check with ThreadInfo with no stack trace (i.e. no safepoint) - ThreadInfo[] infos = TM.getThreadInfo(TM.getAllThreadIds()); - doCheck(infos, lock, expectedThreads); + ThreadInfo[] allThreadInfos = TM.getThreadInfo(TM.getAllThreadIds()); + doCheck(allThreadInfos, lock, expectedThreads); // Check with ThreadInfo with stack trace - infos = TM.getThreadInfo(TM.getAllThreadIds(), 1); - doCheck(infos, lock, expectedThreads); + allThreadInfos = TM.getThreadInfo(TM.getAllThreadIds(), 1); + doCheck(allThreadInfos, lock, expectedThreads); } private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThreads) @@ -434,6 +448,9 @@ private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThre ThreadInfo ownerInfo = null; // Find the thread who is blocking on lock for (ThreadInfo info : infos) { + if (info == null) { + continue; // Missing thread, e.g. completed. Ignore. + } String blockedLock = info.getLockName(); if (lock.equals(blockedLock)) { log("%s blocked on %s", info.getThreadName(), blockedLock); @@ -445,11 +462,19 @@ private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThre "Can't retrieve ThreadInfo for the blocked thread"); } + // Follow chain of locks: long[] threads = new long[10]; int count = 0; threads[count++] = ownerInfo.getThreadId(); while (ownerInfo.getThreadState() == Thread.State.BLOCKED) { ownerInfo = findOwnerInfo(infos, lock); + log("ownerInfo = %s", ownerInfo); + if (ownerInfo.getThreadName().contains("ForkJoinPool")) { + // Ignore e.g. "ForkJoinPool-1-worker-1" waiting on a VirtualThread + log ("skipping %s", ownerInfo); + lock = ownerInfo.getLockName(); + continue; + } threads[count++] = ownerInfo.getThreadId(); log(" Owner = %s id = %d", ownerInfo.getThreadName(), @@ -468,14 +493,19 @@ private static void doCheck(ThreadInfo[] infos, String lock, long[] expectedThre throw new RuntimeException("TEST FAILED: " + "Expected chain of threads not matched; current count =" + count); } + int failures = 0; for (int i = 0; i < count; i++) { if (threads[i] != expectedThreads[i]) { log("TEST FAILED: Unexpected thread in the chain %s expected to be %s", threads[i], expectedThreads[i] ); + failures++; } } + if (failures > 0) { + throw new RuntimeException("TEST FAILED: " + failures + " unexpected thread(s)."); + } } private static void log(String format, Object ... args) { diff --git a/test/jdk/java/util/Locale/Bug8179071.java b/test/jdk/java/util/Locale/AliasesShouldBeRecognizedInCLDR.java similarity index 96% rename from test/jdk/java/util/Locale/Bug8179071.java rename to test/jdk/java/util/Locale/AliasesShouldBeRecognizedInCLDR.java index 97e6b0118a3..fa41aeea07c 100644 --- a/test/jdk/java/util/Locale/Bug8179071.java +++ b/test/jdk/java/util/Locale/AliasesShouldBeRecognizedInCLDR.java @@ -26,7 +26,7 @@ * @bug 8179071 8202537 8231273 8251317 * @summary Test that language aliases of CLDR supplemental metadata are handled correctly. * @modules jdk.localedata - * @run junit/othervm -Djava.locale.providers=CLDR Bug8179071 + * @run junit/othervm -Djava.locale.providers=CLDR AliasesShouldBeRecognizedInCLDR */ /* @@ -49,7 +49,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -public class Bug8179071 { +public class AliasesShouldBeRecognizedInCLDR { /* * Deprecated and Legacy tags. diff --git a/test/jdk/java/util/Locale/Bug4518797.java b/test/jdk/java/util/Locale/HashCodeShouldBeThreadSafe.java similarity index 90% rename from test/jdk/java/util/Locale/Bug4518797.java rename to test/jdk/java/util/Locale/HashCodeShouldBeThreadSafe.java index 5f65b2b0639..70f6f44d36a 100644 --- a/test/jdk/java/util/Locale/Bug4518797.java +++ b/test/jdk/java/util/Locale/HashCodeShouldBeThreadSafe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2023, 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 @@ -24,14 +24,18 @@ * @test * @bug 4518797 * @summary Make sure that hashCode() and read/writeObject() are thread-safe. - * @run main Bug4518797 10 + * @run main HashCodeShouldBeThreadSafe 10 */ -import java.util.*; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Locale; -// Usage: java Bug4518797 [duration] -public class Bug4518797 { +// Usage: java HashCodeShouldBeThreadSafe [duration] +public class HashCodeShouldBeThreadSafe { static volatile boolean runrun = true; static volatile String message = null; diff --git a/test/jdk/java/util/Locale/Bug4184873Test.java b/test/jdk/java/util/Locale/LegacyCodesClassInvariant.java similarity index 90% rename from test/jdk/java/util/Locale/Bug4184873Test.java rename to test/jdk/java/util/Locale/LegacyCodesClassInvariant.java index 817881000f2..c19a74516a0 100644 --- a/test/jdk/java/util/Locale/Bug4184873Test.java +++ b/test/jdk/java/util/Locale/LegacyCodesClassInvariant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,10 @@ */ /* @test + @bug 4184873 @summary test that locale invariants are preserved across serialization @library /java/text/testlib - @run main Bug4184873Test - @bug 4184873 + @run main LegacyCodesClassInvariant */ /* * This file is available under and governed by the GNU General Public @@ -61,18 +61,22 @@ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ -import java.util.*; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Locale; /** * A Locale can never contain the following language codes: he, yi or id. */ -public class Bug4184873Test extends IntlTest { +public class LegacyCodesClassInvariant extends IntlTest { public static void main(String[] args) throws Exception { if (args.length == 1 && args[0].equals("prepTest")) { prepTest(); } else { - new Bug4184873Test().run(args); + new LegacyCodesClassInvariant().run(args); } } @@ -104,7 +108,7 @@ private void verify(String lang) { private ObjectInputStream getStream(String lang) { try { - final File f = new File(System.getProperty("test.src", "."), "Bug4184873_"+lang); + final File f = new File(System.getProperty("test.src", "."), "LegacyCodesClassInvariant_"+lang); return new ObjectInputStream(new FileInputStream(f)); } catch (Exception e) { errln(e.toString()); @@ -125,7 +129,7 @@ private static void prepTest() { private static void outputLocale(String lang) { try { ObjectOutputStream out = new ObjectOutputStream( - new FileOutputStream("Bug4184873_"+lang)); + new FileOutputStream("LegacyCodesClassInvariant_"+lang)); out.writeObject(Locale.of(lang, "XX")); out.close(); } catch (Exception e) { diff --git a/test/jdk/java/util/Locale/Bug4184873_he b/test/jdk/java/util/Locale/LegacyCodesClassInvariant_he similarity index 100% rename from test/jdk/java/util/Locale/Bug4184873_he rename to test/jdk/java/util/Locale/LegacyCodesClassInvariant_he diff --git a/test/jdk/java/util/Locale/Bug4184873_id b/test/jdk/java/util/Locale/LegacyCodesClassInvariant_id similarity index 100% rename from test/jdk/java/util/Locale/Bug4184873_id rename to test/jdk/java/util/Locale/LegacyCodesClassInvariant_id diff --git a/test/jdk/java/util/Locale/Bug4184873_yi b/test/jdk/java/util/Locale/LegacyCodesClassInvariant_yi similarity index 100% rename from test/jdk/java/util/Locale/Bug4184873_yi rename to test/jdk/java/util/Locale/LegacyCodesClassInvariant_yi diff --git a/test/jdk/java/util/Locale/Bug7069824.java b/test/jdk/java/util/Locale/LocaleMatchingTest.java similarity index 98% rename from test/jdk/java/util/Locale/Bug7069824.java rename to test/jdk/java/util/Locale/LocaleMatchingTest.java index 905cde17d50..975e4567e18 100644 --- a/test/jdk/java/util/Locale/Bug7069824.java +++ b/test/jdk/java/util/Locale/LocaleMatchingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, 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,11 +25,19 @@ * @test * @bug 7069824 8042360 8032842 8175539 8210443 8242010 8276302 * @summary Verify implementation for Locale matching. - * @run testng/othervm Bug7069824 + * @run testng/othervm LocaleMatchingTest */ -import java.util.*; -import java.util.Locale.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Locale.FilteringMode; +import java.util.Locale.LanguageRange; +import java.util.Map; + import static java.util.Locale.FilteringMode.*; import static java.util.Locale.LanguageRange.*; import static org.testng.Assert.*; @@ -37,7 +45,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -public class Bug7069824 { +public class LocaleMatchingTest { @DataProvider(name = "LRConstructorData") Object[][] LRConstructorData() { diff --git a/test/jdk/java/util/Locale/Bug4152725.java b/test/jdk/java/util/Locale/LocaleShouldSetFromCLI.java similarity index 87% rename from test/jdk/java/util/Locale/Bug4152725.java rename to test/jdk/java/util/Locale/LocaleShouldSetFromCLI.java index 54392de239a..18432eecd07 100644 --- a/test/jdk/java/util/Locale/Bug4152725.java +++ b/test/jdk/java/util/Locale/LocaleShouldSetFromCLI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2023, 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 @@ -26,24 +26,24 @@ * @summary Verify that the default locale can be specified from the * command line. * @run main/othervm -Duser.language=de -Duser.country=DE -Duser.variant=EURO - * Bug4152725 de_DE_EURO + * LocaleShouldSetFromCLI de_DE_EURO * @run main/othervm -Duser.language=ja -Duser.country= -Duser.variant= - * Bug4152725 ja + * LocaleShouldSetFromCLI ja * @run main/othervm -Duser.language=en -Duser.country=SG -Duser.variant= - * Bug4152725 en_SG + * LocaleShouldSetFromCLI en_SG * @run main/othervm -Duser.language= -Duser.country=DE -Duser.variant=EURO - * Bug4152725 _DE_EURO + * LocaleShouldSetFromCLI _DE_EURO * @run main/othervm -Duser.language=ja -Duser.country= -Duser.variant=YOMI - * Bug4152725 ja__YOMI + * LocaleShouldSetFromCLI ja__YOMI * @run main/othervm -Duser.language= -Duser.country= -Duser.variant=EURO - * Bug4152725 __EURO + * LocaleShouldSetFromCLI __EURO * @run main/othervm -Duser.language=de -Duser.region=DE_EURO - * Bug4152725 de_DE_EURO + * LocaleShouldSetFromCLI de_DE_EURO */ import java.util.Locale; -public class Bug4152725 { +public class LocaleShouldSetFromCLI { public static void main(String[] args) { diff --git a/test/jdk/java/util/Locale/Bug8135061.java b/test/jdk/java/util/Locale/LookupOnValidRangeTest.java similarity index 97% rename from test/jdk/java/util/Locale/Bug8135061.java rename to test/jdk/java/util/Locale/LookupOnValidRangeTest.java index 0e59a9ecbd9..cbf889f0428 100644 --- a/test/jdk/java/util/Locale/Bug8135061.java +++ b/test/jdk/java/util/Locale/LookupOnValidRangeTest.java @@ -26,7 +26,7 @@ * @bug 8135061 * @summary Checks that the Locale.lookup executes properly without throwing * any exception for some specific language ranges - * @run junit Bug8135061 + * @run junit LookupOnValidRangeTest */ import java.util.Collection; @@ -40,7 +40,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -public class Bug8135061 { +public class LookupOnValidRangeTest { /** * Lookup should run without throwing any exception and return null as diff --git a/test/jdk/java/util/Locale/Bug8035133.java b/test/jdk/java/util/Locale/MatchEmptyWeightCorrectly.java similarity index 98% rename from test/jdk/java/util/Locale/Bug8035133.java rename to test/jdk/java/util/Locale/MatchEmptyWeightCorrectly.java index f5f532e3cc6..f69873b566c 100644 --- a/test/jdk/java/util/Locale/Bug8035133.java +++ b/test/jdk/java/util/Locale/MatchEmptyWeightCorrectly.java @@ -25,7 +25,7 @@ * @bug 8035133 * @summary Checks that the tags matching the range with quality weight q=0 * e.g. en;q=0 must be elimited and must not be the part of output - * @run junit Bug8035133 + * @run junit MatchEmptyWeightCorrectly */ import java.util.ArrayList; @@ -40,7 +40,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class Bug8035133 { +public class MatchEmptyWeightCorrectly { // Ensure weights with 'q=0' work as expected during lookup @ParameterizedTest diff --git a/test/jdk/java/util/Locale/Bug6989440.java b/test/jdk/java/util/Locale/ProviderPoolMultiThreadAccess.java similarity index 94% rename from test/jdk/java/util/Locale/Bug6989440.java rename to test/jdk/java/util/Locale/ProviderPoolMultiThreadAccess.java index 9dfb911e859..7acca68b1df 100644 --- a/test/jdk/java/util/Locale/Bug6989440.java +++ b/test/jdk/java/util/Locale/ProviderPoolMultiThreadAccess.java @@ -27,8 +27,8 @@ * @summary Verify ConcurrentModificationException is not thrown with multiple * thread accesses. * @modules java.base/sun.util.locale.provider - * @compile -XDignore.symbol.file=true Bug6989440.java - * @run junit Bug6989440 + * @compile -XDignore.symbol.file=true ProviderPoolMultiThreadAccess.java + * @run junit ProviderPoolMultiThreadAccess */ import java.text.spi.DateFormatProvider; import java.util.spi.LocaleNameProvider; @@ -39,7 +39,7 @@ import org.junit.jupiter.api.Test; -public class Bug6989440 { +public class ProviderPoolMultiThreadAccess { static volatile boolean failed; // false static final int THREADS = 50; diff --git a/test/jdk/java/util/Locale/Bug8166994.java b/test/jdk/java/util/Locale/SubsequentRangeParsingTest.java similarity index 96% rename from test/jdk/java/util/Locale/Bug8166994.java rename to test/jdk/java/util/Locale/SubsequentRangeParsingTest.java index e39627ac709..b160b3a692e 100644 --- a/test/jdk/java/util/Locale/Bug8166994.java +++ b/test/jdk/java/util/Locale/SubsequentRangeParsingTest.java @@ -23,12 +23,12 @@ /* * @test - * @bug 8166884 + * @bug 8166994 * @summary Checks the subsequent call to parse the same language ranges * which must generate the same list of language ranges * i.e. the priority list containing equivalents, as in the * first call - * @run junit Bug8166994 + * @run junit SubsequentRangeParsingTest */ import java.util.Arrays; @@ -43,7 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class Bug8166994 { +public class SubsequentRangeParsingTest { /* * Checks that consecutive calls to parse the same language ranges diff --git a/test/jdk/java/util/Locale/Bug8159420.java b/test/jdk/java/util/Locale/TurkishLangRangeTest.java similarity index 97% rename from test/jdk/java/util/Locale/Bug8159420.java rename to test/jdk/java/util/Locale/TurkishLangRangeTest.java index 2e6de243b36..44366bbc0d0 100644 --- a/test/jdk/java/util/Locale/Bug8159420.java +++ b/test/jdk/java/util/Locale/TurkishLangRangeTest.java @@ -31,8 +31,8 @@ * e.g. "HI-Deva".toLowerCase() in the Turkish locale returns * "hı-deva", where 'ı' is the LATIN SMALL LETTER DOTLESS I character * which is not allowed in the language ranges/tags. - * @compile -encoding utf-8 Bug8159420.java - * @run junit/othervm -Duser.language=tr -Duser.country=TR Bug8159420 + * @compile -encoding utf-8 TurkishLangRangeTest.java + * @run junit/othervm -Duser.language=tr -Duser.country=TR TurkishLangRangeTest */ import java.util.ArrayList; @@ -58,7 +58,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -public class Bug8159420 { +public class TurkishLangRangeTest { /* * Ensure parse() does not throw IllegalArgumentException for the Turkish Locale diff --git a/test/jdk/java/util/Locale/bug4123285.html b/test/jdk/java/util/Locale/bug4123285.html deleted file mode 100644 index 7cb7a3d07d8..00000000000 --- a/test/jdk/java/util/Locale/bug4123285.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/jdk/java/util/Locale/bug4123285.java b/test/jdk/java/util/Locale/bug4123285.java deleted file mode 100644 index 23cbb8ad5bd..00000000000 --- a/test/jdk/java/util/Locale/bug4123285.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -import java.util.Locale; - -public class bug4123285 extends java.applet.Applet { - public void start() { - System.out.println("Hello, world!"); - Locale[] systemLocales = null; - try { - System.out.println("Default locale = " + Locale.getDefault()); - systemLocales = Locale.getAvailableLocales(); - System.out.println("Found " + systemLocales.length + " locales:"); - Locale[] locales = new Locale[systemLocales.length]; - for (int i = 0; i < locales.length; i++) { - Locale lowest = null; - for (int j = 0; j < systemLocales.length; j++) { - if (i > 0 && locales[i - 1].toString().compareTo(systemLocales[j].toString()) >= 0) - continue; - if (lowest == null || systemLocales[j].toString().compareTo(lowest.toString()) < 0) - lowest = systemLocales[j]; - } - locales[i] = lowest; - } - for (int i = 0; i < locales.length; i++) { - if (locales[i].getCountry().length() == 0) - System.out.println(" " + locales[i].getDisplayLanguage() + ":"); - else { - if (locales[i].getVariant().length() == 0) - System.out.println(" " + locales[i].getDisplayCountry()); - else - System.out.println(" " + locales[i].getDisplayCountry() + ", " - + locales[i].getDisplayVariant()); - } - } - } - catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/test/jdk/javax/print/attribute/SidesAttributeTest.java b/test/jdk/javax/print/attribute/SidesAttributeTest.java new file mode 100644 index 00000000000..60454f30407 --- /dev/null +++ b/test/jdk/javax/print/attribute/SidesAttributeTest.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug JDK-8311033 + * @summary [macos] PrinterJob does not take into account Sides attribute + * @run main/manual SidesAttributeTest + */ + +import javax.print.PrintService; +import javax.print.attribute.Attribute; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Sides; +import javax.swing.*; +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class SidesAttributeTest { + + private static final long TIMEOUT = 10 * 60_000; + private static volatile boolean testPassed = true; + private static volatile boolean testFinished = false; + private static volatile boolean timeout = false; + + private static volatile int testCount; + private static volatile int testTotalCount; + + public static void main(String[] args) throws Exception { + + SwingUtilities.invokeLater(() -> { + + Set supportedSides = getSupportedSidesAttributes(); + if (supportedSides.size() > 1) { + testTotalCount = supportedSides.size(); + testPrint(Sides.ONE_SIDED, supportedSides); + testPrint(Sides.DUPLEX, supportedSides); + testPrint(Sides.TUMBLE, supportedSides); + } + testFinished = true; + }); + + long time = System.currentTimeMillis() + TIMEOUT; + + while (System.currentTimeMillis() < time) { + if (!testPassed || testFinished) { + break; + } + Thread.sleep(500); + } + + timeout = true; + + closeDialogs(); + + if (!testPassed) { + throw new Exception("Test failed!"); + } + + if (testCount != testTotalCount) { + throw new Exception( + "Timeout: " + testCount + " tests passed out from " + testTotalCount); + } + } + + private static void print(Sides sides) throws PrinterException { + PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet(); + attr.add(sides); + + for (Attribute attribute : attr.toArray()) { + System.out.printf("Used print request attribute: %s%n", attribute); + } + + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(new SidesAttributePrintable(sides)); + + job.print(attr); + } + + private static class SidesAttributePrintable implements Printable { + + private final Sides sidesAttr; + + public SidesAttributePrintable(Sides sidesAttr) { + this.sidesAttr = sidesAttr; + } + + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + + if (pageIndex >= 2) { + return NO_SUCH_PAGE; + } + + int x = (int) (pageFormat.getImageableX() + pageFormat.getImageableWidth() / 10); + int y = (int) (pageFormat.getImageableY() + pageFormat.getImageableHeight() / 5); + + Graphics2D g = (Graphics2D) graphics; + String text = getPageText(sidesAttr, pageIndex + 1); + g.drawString(text, x, y); + return PAGE_EXISTS; + } + } + + private static String getPageText(Sides sides, int page) { + return String.format("Page: %d - %s", page, getSidesText(sides)); + } + + private static String getSidesText(Sides sides) { + if (Sides.ONE_SIDED.equals(sides)) { + return "ONE_SIDED"; + } else if (Sides.TWO_SIDED_SHORT_EDGE.equals(sides)) { + return "TWO_SIDED_SHORT_EDGE (TUMBLE)"; + } else if (Sides.TWO_SIDED_LONG_EDGE.equals(sides)) { + return "TWO_SIDED_LONG_EDGE (DUPLEX)"; + } + throw new RuntimeException("Unknown sides attribute: " + sides); + } + + private static String getSidesDescription(Sides sides) { + if (Sides.ONE_SIDED.equals(sides)) { + return "a one-sided document"; + } else if (Sides.TWO_SIDED_SHORT_EDGE.equals(sides)) { + return "double-sided document along the short edge of the paper"; + } else if (Sides.TWO_SIDED_LONG_EDGE.equals(sides)) { + return "double-sided document along the long edge of the paper"; + } + throw new RuntimeException("Unknown sides attribute: " + sides); + } + + private static Set getSupportedSidesAttributes() { + Set supportedSides = new HashSet<>(); + + PrinterJob printerJob = PrinterJob.getPrinterJob(); + PrintService service = printerJob.getPrintService(); + + Object obj = service.getSupportedAttributeValues(Sides.class, null, null); + if (obj instanceof Attribute[]) { + Attribute[] attr = (Attribute[]) obj; + Collections.addAll(supportedSides, attr); + } + + return supportedSides; + } + + private static void pass() { + testCount++; + } + + private static void fail(Sides sides) { + System.out.printf("Failed test: %s%n", getSidesText(sides)); + testPassed = false; + } + + private static void runPrint(Sides sides) { + try { + print(sides); + } catch (PrinterException e) { + fail(sides); + e.printStackTrace(); + } + } + + private static void testPrint(Sides sides, Set supportedSides) { + + if (!supportedSides.contains(sides) || !testPassed || timeout) { + return; + } + + String[] instructions = { + "Up to " + testTotalCount + " tests will run and it will test all the cases", + "supported by the printer.", + "", + "The test is " + (testCount + 1) + " from " + testTotalCount + ".", + "", + "On-screen inspection is not possible for this printing-specific", + "test therefore its only output is two printed pages (one or two sided).", + "To be able to run this test it is required to have a default", + "printer configured in your user environment.", + "", + "Visual inspection of the printed pages is needed.", + "A passing test will print 2 pages:", + " - the first page with the text: " + getPageText(sides, 1), + " - the second page with the text: " + getPageText(sides, 2), + "", + "The test fails if the pages are not printed according to the tested", + getSidesText(sides) + " attribute where " + getSidesDescription(sides), + "needs to be printed.", + "", + }; + + String title = String.format("Print %s sides test: %d from %d", + getSidesText(sides), testCount + 1, testTotalCount); + final JDialog dialog = new JDialog((Frame) null, title, Dialog.ModalityType.DOCUMENT_MODAL); + JTextArea textArea = new JTextArea(String.join("\n", instructions)); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + final JButton passButton = new JButton("PASS"); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + pass(); + dialog.dispose(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + fail(sides); + dialog.dispose(); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + runPrint(sides); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.out.println("Dialog closing"); + fail(sides); + } + }); + } + + private static void closeDialogs() { + for (Window w : Dialog.getWindows()) { + w.dispose(); + } + } +} diff --git a/test/jdk/jdk/jfr/jvm/TestChunkIntegrity.java b/test/jdk/jdk/jfr/jvm/TestChunkIntegrity.java index 0ca887609f4..aba19bd37b7 100644 --- a/test/jdk/jdk/jfr/jvm/TestChunkIntegrity.java +++ b/test/jdk/jdk/jfr/jvm/TestChunkIntegrity.java @@ -59,7 +59,7 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib /test/jdk - * @run main/othervm jdk.jfr.jvm.TestChunkIntegrity + * @run main/othervm/timeout=300 jdk.jfr.jvm.TestChunkIntegrity */ public class TestChunkIntegrity { diff --git a/test/langtools/jdk/javadoc/doclet/testAnnotationTypes/TestAnnotationTypes.java b/test/langtools/jdk/javadoc/doclet/testAnnotationTypes/TestAnnotationTypes.java index 9b2fc5e95bb..84b03b85513 100644 --- a/test/langtools/jdk/javadoc/doclet/testAnnotationTypes/TestAnnotationTypes.java +++ b/test/langtools/jdk/javadoc/doclet/testAnnotationTypes/TestAnnotationTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, 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 @@ -24,7 +24,7 @@ /* * @test * @bug 4973609 8015249 8025633 8026567 6469561 8071982 8162363 8182765 8223364 - 8242056 8261976 8223358 + 8242056 8261976 8223358 8313204 * @summary Make sure that annotation types with 0 members does not have * extra HR tags. * @library ../../lib @@ -185,4 +185,22 @@ public void testLinkSource() { """ public @interface AnnotationTypeField"""); } + + @Test + public void testSectionOrdering() { + javadoc("-d", "out-3", + "-linksource", + "--no-platform-links", + "-sourcepath", testSrc, + "pkg"); + checkExit(Exit.OK); + + checkOrder("pkg/AnnotationTypeField.html", + "