diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index fa5a8a61a0a..29750b485e4 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -84,7 +84,7 @@ jobs: - target-cpu: riscv64 gnu-arch: riscv64 debian-arch: riscv64 - debian-repository: https://httpredir.debian.org/debian/ + debian-repository: https://snapshot.debian.org/archive/debian/20240228T034848Z/ debian-version: sid tolerate-sysroot-errors: true diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 15251358a01..0ca2a226a96 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -1372,6 +1372,7 @@ private static Map coverageLevelsMap() throws Exception { private static void generateTZDBShortNamesMap() throws IOException { Files.walk(Path.of(tzDataDir), 1, FileVisitOption.FOLLOW_LINKS) .filter(p -> p.toFile().isFile()) + .filter(p -> p.getFileName().toString().matches("africa|antarctica|asia|australasia|backward|etcetera|europe|northamerica|southamerica")) .forEach(p -> { try { String zone = null; @@ -1394,43 +1395,41 @@ private static void generateTZDBShortNamesMap() throws IOException { } // remove comments in-line line = line.replaceAll("[ \t]*#.*", ""); - + var tokens = line.split("[ \t]+", -1); + var token0len = tokens.length > 0 ? tokens[0].length() : 0; // Zone line - if (line.startsWith("Zone")) { + if (token0len > 0 && tokens[0].regionMatches(true, 0, "Zone", 0, token0len)) { if (zone != null) { tzdbShortNamesMap.put(zone, format + NBSP + rule); } - var zl = line.split("[ \t]+", -1); - zone = zl[1]; - rule = zl[3]; - format = flipIfNeeded(inVanguard, zl[4]); + zone = tokens[1]; + rule = tokens[3]; + format = flipIfNeeded(inVanguard, tokens[4]); } else { if (zone != null) { - if (line.startsWith("Rule") || - line.startsWith("Link")) { + if (token0len > 0 && + (tokens[0].regionMatches(true, 0, "Rule", 0, token0len) || + tokens[0].regionMatches(true, 0, "Link", 0, token0len))) { tzdbShortNamesMap.put(zone, format + NBSP + rule); zone = null; rule = null; format = null; } else { - var s = line.split("[ \t]+", -1); - rule = s[2]; - format = flipIfNeeded(inVanguard, s[3]); + rule = tokens[2]; + format = flipIfNeeded(inVanguard, tokens[3]); } } } // Rule line - if (line.startsWith("Rule")) { - var rl = line.split("[ \t]+", -1); - tzdbSubstLetters.put(rl[1] + NBSP + (rl[8].equals("0") ? STD : DST), - rl[9].replace(NO_SUBST, "")); + if (token0len > 0 && tokens[0].regionMatches(true, 0, "Rule", 0, token0len)) { + tzdbSubstLetters.put(tokens[1] + NBSP + (tokens[8].equals("0") ? STD : DST), + tokens[9].replace(NO_SUBST, "")); } // Link line - if (line.startsWith("Link")) { - var ll = line.split("[ \t]+", -1); - tzdbLinks.put(ll[2], ll[1]); + if (token0len > 0 && tokens[0].regionMatches(true, 0, "Link", 0, token0len)) { + tzdbLinks.put(tokens[2], tokens[1]); } } diff --git a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java index d82e58e3420..ecca3c69c06 100644 --- a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java +++ b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 @@ -164,7 +164,8 @@ private void load(List files) throws IOException { } continue; } - if (line.startsWith("Zone")) { // parse Zone line + int token0len = tokens.length > 0 ? tokens[0].length() : line.length(); + if (line.regionMatches(true, 0, "Zone", 0, token0len)) { // parse Zone line String name = tokens[1]; if (excludedZones.contains(name)){ continue; @@ -182,13 +183,13 @@ private void load(List files) throws IOException { if (zLine.parse(tokens, 2)) { openZone = null; } - } else if (line.startsWith("Rule")) { // parse Rule line + } else if (line.regionMatches(true, 0, "Rule", 0, token0len)) { // parse Rule line String name = tokens[1]; if (!rules.containsKey(name)) { rules.put(name, new ArrayList(10)); } rules.get(name).add(new RuleLine().parse(tokens)); - } else if (line.startsWith("Link")) { // parse link line + } else if (line.regionMatches(true, 0, "Link", 0, token0len)) { // parse link line if (tokens.length >= 3) { String realId = tokens[1]; String aliasId = tokens[2]; @@ -304,7 +305,7 @@ private void parse(String[] tokens, int off) { month = parseMonth(tokens[off++]); if (off < tokens.length) { String dayRule = tokens[off++]; - if (dayRule.startsWith("last")) { + if (dayRule.regionMatches(true, 0, "last", 0, 4)) { dayOfMonth = -1; dayOfWeek = parseDayOfWeek(dayRule.substring(4)); adjustForwards = false; @@ -355,42 +356,45 @@ private void parse(String[] tokens, int off) { } int parseYear(String year, int defaultYear) { - switch (year.toLowerCase()) { - case "min": return 1900; - case "max": return Year.MAX_VALUE; - case "only": return defaultYear; - } + int len = year.length(); + + if (year.regionMatches(true, 0, "minimum", 0, len)) return 1900; + if (year.regionMatches(true, 0, "maximum", 0, len)) return Year.MAX_VALUE; + if (year.regionMatches(true, 0, "only", 0, len)) return defaultYear; + return Integer.parseInt(year); } Month parseMonth(String mon) { - switch (mon) { - case "Jan": return Month.JANUARY; - case "Feb": return Month.FEBRUARY; - case "Mar": return Month.MARCH; - case "Apr": return Month.APRIL; - case "May": return Month.MAY; - case "Jun": return Month.JUNE; - case "Jul": return Month.JULY; - case "Aug": return Month.AUGUST; - case "Sep": return Month.SEPTEMBER; - case "Oct": return Month.OCTOBER; - case "Nov": return Month.NOVEMBER; - case "Dec": return Month.DECEMBER; - } + int len = mon.length(); + + if (mon.regionMatches(true, 0, "January", 0, len)) return Month.JANUARY; + if (mon.regionMatches(true, 0, "February", 0, len)) return Month.FEBRUARY; + if (mon.regionMatches(true, 0, "March", 0, len)) return Month.MARCH; + if (mon.regionMatches(true, 0, "April", 0, len)) return Month.APRIL; + if (mon.regionMatches(true, 0, "May", 0, len)) return Month.MAY; + if (mon.regionMatches(true, 0, "June", 0, len)) return Month.JUNE; + if (mon.regionMatches(true, 0, "July", 0, len)) return Month.JULY; + if (mon.regionMatches(true, 0, "August", 0, len)) return Month.AUGUST; + if (mon.regionMatches(true, 0, "September", 0, len)) return Month.SEPTEMBER; + if (mon.regionMatches(true, 0, "October", 0, len)) return Month.OCTOBER; + if (mon.regionMatches(true, 0, "November", 0, len)) return Month.NOVEMBER; + if (mon.regionMatches(true, 0, "December", 0, len)) return Month.DECEMBER; + throw new IllegalArgumentException("Unknown month: " + mon); } DayOfWeek parseDayOfWeek(String dow) { - switch (dow) { - case "Mon": return DayOfWeek.MONDAY; - case "Tue": return DayOfWeek.TUESDAY; - case "Wed": return DayOfWeek.WEDNESDAY; - case "Thu": return DayOfWeek.THURSDAY; - case "Fri": return DayOfWeek.FRIDAY; - case "Sat": return DayOfWeek.SATURDAY; - case "Sun": return DayOfWeek.SUNDAY; - } + int len = dow.length(); + + if (dow.regionMatches(true, 0, "Monday", 0, len)) return DayOfWeek.MONDAY; + if (dow.regionMatches(true, 0, "Tuesday", 0, len)) return DayOfWeek.TUESDAY; + if (dow.regionMatches(true, 0, "Wednesday", 0, len)) return DayOfWeek.WEDNESDAY; + if (dow.regionMatches(true, 0, "Thursday", 0, len)) return DayOfWeek.THURSDAY; + if (dow.regionMatches(true, 0, "Friday", 0, len)) return DayOfWeek.FRIDAY; + if (dow.regionMatches(true, 0, "Saturday", 0, len)) return DayOfWeek.SATURDAY; + if (dow.regionMatches(true, 0, "Sunday", 0, len)) return DayOfWeek.SUNDAY; + throw new IllegalArgumentException("Unknown day-of-week: " + dow); } diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 901ae502999..3117c751498 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -2181,7 +2181,8 @@ void SharedRuntime::generate_deopt_blob() { pad += 512; // Increase the buffer size when compiling for JVMCI } #endif - CodeBuffer buffer("deopt_blob", 2048+pad, 1024); + const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBuffer buffer(name, 2048+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; OopMap* map = nullptr; @@ -2565,20 +2566,23 @@ uint SharedRuntime::out_preserve_stack_slots() { // Generate a special Compile2Runtime blob that saves all registers, // and setup oopmap. // -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { + assert(is_polling_page_id(id), "expected a polling page stub id"); + ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); OopMap* map; // Allocate space for the code. Setup code generation tools. - CodeBuffer buffer("handler_blob", 2048, 1024); + const char* name = SharedRuntime::stub_name(id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); address start = __ pc(); address call_pc = nullptr; int frame_size_in_words; - bool cause_return = (poll_type == POLL_AT_RETURN); - RegisterSaver reg_save(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */); + bool cause_return = (id == SharedStubId::polling_page_return_handler_id); + RegisterSaver reg_save(id == SharedStubId::polling_page_vectors_safepoint_handler_id /* save_vectors */); // When the signal occurred, the LR was either signed and stored on the stack (in which // case it will be restored from the stack before being used) or unsigned and not stored @@ -2690,12 +2694,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // but since this is generic code we don't know what they are and the caller // must do any gc of the args. // -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_resolve_id(id), "expected a resolve stub id"); // allocate space for the code ResourceMark rm; + const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1000, 512); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -2787,7 +2793,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // otherwise assume that stack unwinding will be initiated, so // caller saved registers were assumed volatile in the compiler. -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { + assert(is_throw_id(id), "expected a throw stub id"); + + const char* name = SharedRuntime::stub_name(id); + // Information about frame layout at time of blocking runtime call. // Note that we only have to preserve callee-saved registers since // the compilers are responsible for supplying a continuation point @@ -2896,7 +2906,8 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { int insts_size = 1024; int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id); + CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2915,7 +2926,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { oop_maps->add_gc_map(the_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; @@ -2934,7 +2945,8 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { int insts_size = 1024; int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id); + CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2953,7 +2965,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { oop_maps->add_gc_map(the_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index f07c1f8e53c..7648e5c5d92 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1360,7 +1360,8 @@ uint SharedRuntime::out_preserve_stack_slots() { //------------------------------generate_deopt_blob---------------------------- void SharedRuntime::generate_deopt_blob() { ResourceMark rm; - CodeBuffer buffer("deopt_blob", 1024, 1024); + const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBuffer buffer(name, 1024, 1024); int frame_size_in_words; OopMapSet* oop_maps; int reexecute_offset; @@ -1601,15 +1602,17 @@ void SharedRuntime::generate_deopt_blob() { // setup oopmap, and calls safepoint code to stop the compiled code for // a safepoint. // -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_polling_page_id(id), "expected a polling page stub id"); ResourceMark rm; - CodeBuffer buffer("handler_blob", 256, 256); + const char* name = SharedRuntime::stub_name(id); + CodeBuffer buffer(name, 256, 256); int frame_size_words; OopMapSet* oop_maps; - bool cause_return = (poll_type == POLL_AT_RETURN); + bool cause_return = (id == SharedStubId::polling_page_return_handler_id); MacroAssembler* masm = new MacroAssembler(&buffer); address start = __ pc(); @@ -1671,10 +1674,12 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t return SafepointBlob::create(&buffer, oop_maps, frame_size_words); } -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_resolve_id(id), "expected a resolve stub id"); ResourceMark rm; + const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1000, 512); int frame_size_words; OopMapSet *oop_maps; @@ -1733,7 +1738,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // Continuation point for throwing of implicit exceptions that are not handled in // the current activation. Fabricates an exception oop and initiates normal // exception dispatching in this frame. -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { + assert(is_throw_id(id), "expected a throw stub id"); + + const char* name = SharedRuntime::stub_name(id); + int insts_size = 128; int locs_size = 32; @@ -1793,7 +1802,8 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { framesize // inclusive of return address }; - CodeBuffer code("jfr_write_checkpoint", 512, 64); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id); + CodeBuffer code(name, 512, 64); MacroAssembler* masm = new MacroAssembler(&code); address start = __ pc(); @@ -1818,7 +1828,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { oop_maps->add_gc_map(frame_complete, map); RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), @@ -1836,7 +1846,8 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { framesize // inclusive of return address }; - CodeBuffer code("jfr_return_lease", 512, 64); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id); + CodeBuffer code(name, 512, 64); MacroAssembler* masm = new MacroAssembler(&code); address start = __ pc(); @@ -1858,7 +1869,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { oop_maps->add_gc_map(frame_complete, map); RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 88d635f2b85..2191b894f6e 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -1859,7 +1859,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { __ stw(R11_scratch1, simm16_offs, tmp); } #endif - __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + __ call_c(copyfunc_addr, relocInfo::runtime_call_type); __ nand(tmp, R3_RET, R3_RET); __ subf(length, tmp, length); @@ -2057,7 +2057,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { int sco_offset = in_bytes(Klass::super_check_offset_offset()); __ lwz(chk_off, sco_offset, super_k); - __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + __ call_c(copyfunc_addr, relocInfo::runtime_call_type); #ifndef PRODUCT if (PrintC1Statistics) { @@ -2181,7 +2181,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { // Arraycopy stubs takes a length in number of elements, so don't scale it. __ mr(len, length); - __ call_c_with_frame_resize(entry, /*stub does not need resized frame*/ 0); + __ call_c(entry, relocInfo::runtime_call_type); if (stub != nullptr) { __ bind(*stub->continuation()); @@ -2862,7 +2862,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, return; } - __ call_c_with_frame_resize(dest, /*no resizing*/ 0); + __ call_c(dest, relocInfo::runtime_call_type); if (info != nullptr) { add_call_info_here(info); } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 081d10f065f..059bb2eae0c 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -404,14 +404,3 @@ void C1_MacroAssembler::null_check(Register r, Label* Lnull) { bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::equal), *Lnull); } } - -address C1_MacroAssembler::call_c_with_frame_resize(address dest, int frame_resize) { - if (frame_resize) { resize_frame(-frame_resize, R0); } -#if defined(ABI_ELFv2) - address return_pc = call_c(dest, relocInfo::runtime_call_type); -#else - address return_pc = call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, dest), relocInfo::runtime_call_type); -#endif - if (frame_resize) { resize_frame(frame_resize, R0); } - return return_pc; -} diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp index c0a3dd3b83c..381cb63f832 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp @@ -89,6 +89,5 @@ void null_check(Register r, Label *Lnull = nullptr); - address call_c_with_frame_resize(address dest, int frame_resize); #endif // CPU_PPC_C1_MACROASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index d212d25b3ad..adddfda4ee7 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -62,7 +62,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, // ARG1 must hold thread address. mr(R3_ARG1, R16_thread); - address return_pc = call_c_with_frame_resize(entry_point, /*No resize, we have a C compatible frame.*/0); + address return_pc = call_c(entry_point); reset_last_Java_frame(); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index c24089ccdd5..a29e0810d52 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -135,15 +135,7 @@ void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) // Call the Interpreter::remove_activation_preserving_args_entry() // func to get the address of the same-named entrypoint in the // generated interpreter code. -#if defined(ABI_ELFv2) - call_c(CAST_FROM_FN_PTR(address, - Interpreter::remove_activation_preserving_args_entry), - relocInfo::none); -#else - call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, - Interpreter::remove_activation_preserving_args_entry), - relocInfo::none); -#endif + call_c(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); // Jump to Interpreter::_remove_activation_preserving_args_entry. mtctr(R3_RET); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index e596f91704c..8449d74d8a8 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1293,11 +1293,7 @@ void MacroAssembler::call_VM_base(Register oop_result, // ARG1 must hold thread address. mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) address return_pc = call_c(entry_point, relocInfo::none); -#else - address return_pc = call_c((FunctionDescriptor*)entry_point, relocInfo::none); -#endif reset_last_Java_frame(); @@ -1318,11 +1314,7 @@ void MacroAssembler::call_VM_base(Register oop_result, void MacroAssembler::call_VM_leaf_base(address entry_point) { BLOCK_COMMENT("call_VM_leaf {"); -#if defined(ABI_ELFv2) - call_c(entry_point, relocInfo::none); -#else - call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::none); -#endif + call_c(entry_point); BLOCK_COMMENT("} call_VM_leaf"); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 9a0cf3d8da0..03ad37a4fb0 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -359,7 +359,7 @@ class MacroAssembler: public Assembler { address call_c(Register function_entry); // For tail calls: only branch, don't link, so callee returns to caller of this function. address call_c_and_return_to_caller(Register function_entry); - address call_c(address function_entry, relocInfo::relocType rt); + address call_c(address function_entry, relocInfo::relocType rt = relocInfo::none); #else // Call a C function via a function descriptor and use full C // calling conventions. Updates and returns _last_calls_return_pc. @@ -367,6 +367,9 @@ class MacroAssembler: public Assembler { // For tail calls: only branch, don't link, so callee returns to caller of this function. address call_c_and_return_to_caller(Register function_descriptor); address call_c(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt); + address call_c(address function_entry, relocInfo::relocType rt = relocInfo::none) { + return call_c((const FunctionDescriptor*)function_entry, rt); + } address call_c_using_toc(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt, Register toc); #endif diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp index 8c3bfd4f37b..dbdc16ee5f1 100644 --- a/src/hotspot/cpu/ppc/runtime_ppc.cpp +++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp @@ -99,12 +99,7 @@ void OptoRuntime::generate_exception_blob() { __ set_last_Java_frame(/*sp=*/R1_SP, noreg); __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c((address) OptoRuntime::handle_exception_C, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, OptoRuntime::handle_exception_C), - relocInfo::none); -#endif + __ call_c((address) OptoRuntime::handle_exception_C); address calls_return_pc = __ last_calls_return_pc(); # ifdef ASSERT __ cmpdi(CCR0, R3_RET, 0); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 98610d21b67..5cf5f7cf73e 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2444,12 +2444,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // The JNI call // -------------------------------------------------------------------------- -#if defined(ABI_ELFv2) __ call_c(native_func, relocInfo::runtime_call_type); -#else - FunctionDescriptor* fd_native_method = (FunctionDescriptor*) native_func; - __ call_c(fd_native_method, relocInfo::runtime_call_type); -#endif // Now, we are back from the native code. @@ -2861,7 +2856,8 @@ void SharedRuntime::generate_deopt_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("deopt_blob", 2048, 1024); + const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBuffer buffer(name, 2048, 1024); InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); Label exec_mode_initialized; int frame_size_in_words; @@ -3211,23 +3207,25 @@ void OptoRuntime::generate_uncommon_trap_blob() { #endif // COMPILER2 // Generate a special Compile2Runtime blob that saves all registers, and setup oopmap. -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_polling_page_id(id), "expected a polling page stub id"); ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); OopMap* map; // Allocate space for the code. Setup code generation tools. - CodeBuffer buffer("handler_blob", 2048, 1024); + const char* name = SharedRuntime::stub_name(id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); address start = __ pc(); int frame_size_in_bytes = 0; RegisterSaver::ReturnPCLocation return_pc_location; - bool cause_return = (poll_type == POLL_AT_RETURN); + bool cause_return = (id == SharedStubId::polling_page_return_handler_id); if (cause_return) { // Nothing to do here. The frame has already been popped in MachEpilogNode. // Register LR already contains the return pc. @@ -3237,7 +3235,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t return_pc_location = RegisterSaver::return_pc_is_thread_saved_exception_pc; } - bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); + bool save_vectors = (id == SharedStubId::polling_page_vectors_safepoint_handler_id); // Save registers, fpu state, and flags. Set R31 = return pc. map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, @@ -3324,11 +3322,13 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // but since this is generic code we don't know what they are and the caller // must do any gc of the args. // -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { + assert(is_resolve_id(id), "expected a resolve stub id"); // allocate space for the code ResourceMark rm; + const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1000, 512); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -3426,7 +3426,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // Note: the routine set_pc_not_at_call_for_caller in // SharedRuntime.cpp requires that this code be generated into a // RuntimeStub. -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { + assert(is_throw_id(id), "expected a throw stub id"); + + const char* name = SharedRuntime::stub_name(id); + ResourceMark rm; const char* timer_msg = "SharedRuntime generate_throw_exception"; TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); @@ -3455,11 +3459,7 @@ RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address r __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c(runtime_entry, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); -#endif + __ call_c(runtime_entry); // Set an oopmap for the call site. oop_maps->add_gc_map((int)(gc_map_pc - start), map); @@ -3749,7 +3749,8 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, // It returns a jobject handle to the event writer. // The handle is dereferenced and the return value is the event writer oop. RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { - CodeBuffer code("jfr_write_checkpoint", 512, 64); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id); + CodeBuffer code(name, 512, 64); MacroAssembler* masm = new MacroAssembler(&code); Register tmp1 = R10_ARG8; @@ -3777,8 +3778,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { oop_maps->add_gc_map(calls_return_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub(code.name(), - &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; @@ -3786,7 +3786,8 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { // For c2: call to return a leased buffer. RuntimeStub* SharedRuntime::generate_jfr_return_lease() { - CodeBuffer code("jfr_return_lease", 512, 64); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id); + CodeBuffer code(name, 512, 64); MacroAssembler* masm = new MacroAssembler(&code); Register tmp1 = R10_ARG8; @@ -3812,8 +3813,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { oop_maps->add_gc_map(calls_return_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub(code.name(), - &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index bb746619616..03dca2aeb9b 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1464,13 +1464,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // native result across the call. No oop is present. __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), - relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), - relocInfo::none); -#endif + __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); __ bind(sync_check_done); diff --git a/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp index 312e5cad963..a0ff429b87a 100644 --- a/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp +++ b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp @@ -74,6 +74,16 @@ InterpreterRuntime::SignatureHandlerGenerator::SignatureHandlerGenerator( _stack_offset = 0; } +// The C ABI specifies: +// "integer scalars narrower than XLEN bits are widened according to the sign +// of their type up to 32 bits, then sign-extended to XLEN bits." +// Applies for both passed in register and stack. +// +// Java uses 32-bit stack slots; jint, jshort, jchar, jbyte uses one slot. +// Native uses 64-bit stack slots for all integer scalar types. +// +// lw loads the Java stack slot, sign-extends and +// sd store this widened integer into a 64 bit native stack slot. void InterpreterRuntime::SignatureHandlerGenerator::pass_int() { const Address src(from(), Interpreter::local_offset_in_bytes(offset())); @@ -82,7 +92,7 @@ void InterpreterRuntime::SignatureHandlerGenerator::pass_int() { __ lw(reg, src); } else { __ lw(x10, src); - __ sw(x10, Address(to(), next_stack_offset())); + __ sd(x10, Address(to(), next_stack_offset())); } } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index a4eaab9b028..cbca9802889 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -5526,15 +5526,21 @@ static int reg2offset_out(VMReg r) { return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; } -// On 64 bit we will store integer like items to the stack as -// 64 bits items (riscv64 abi) even though java would only store -// 32bits for a parameter. On 32bit it will simply be 32 bits -// So this routine will do 32->32 on 32bit and 32->64 on 64bit +// The C ABI specifies: +// "integer scalars narrower than XLEN bits are widened according to the sign +// of their type up to 32 bits, then sign-extended to XLEN bits." +// Applies for both passed in register and stack. +// +// Java uses 32-bit stack slots; jint, jshort, jchar, jbyte uses one slot. +// Native uses 64-bit stack slots for all integer scalar types. +// +// lw loads the Java stack slot, sign-extends and +// sd store this widened integer into a 64 bit native stack slot. void MacroAssembler::move32_64(VMRegPair src, VMRegPair dst, Register tmp) { if (src.first()->is_stack()) { if (dst.first()->is_stack()) { // stack to stack - ld(tmp, Address(fp, reg2offset_in(src.first()))); + lw(tmp, Address(fp, reg2offset_in(src.first()))); sd(tmp, Address(sp, reg2offset_out(dst.first()))); } else { // stack to reg diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index ffd904aed47..879fd922722 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -2057,7 +2057,8 @@ void SharedRuntime::generate_deopt_blob() { pad += 512; // Increase the buffer size when compiling for JVMCI } #endif - CodeBuffer buffer("deopt_blob", 2048 + pad, 1024); + const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBuffer buffer(name, 2048 + pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words = -1; OopMap* map = nullptr; @@ -2435,22 +2436,25 @@ uint SharedRuntime::out_preserve_stack_slots() { // Generate a special Compile2Runtime blob that saves all registers, // and setup oopmap. // -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { + assert(is_polling_page_id(id), "expected a polling page stub id"); + ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); assert_cond(oop_maps != nullptr); OopMap* map = nullptr; // Allocate space for the code. Setup code generation tools. - CodeBuffer buffer("handler_blob", 2048, 1024); + const char* name = SharedRuntime::stub_name(id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); address start = __ pc(); address call_pc = nullptr; int frame_size_in_words = -1; - bool cause_return = (poll_type == POLL_AT_RETURN); - RegisterSaver reg_saver(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */); + bool cause_return = (id == SharedStubId::polling_page_return_handler_id); + RegisterSaver reg_saver(id == SharedStubId::polling_page_vectors_safepoint_handler_id /* save_vectors */); // Save Integer and Float registers. map = reg_saver.save_live_registers(masm, 0, &frame_size_in_words); @@ -2556,12 +2560,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // but since this is generic code we don't know what they are and the caller // must do any gc of the args. // -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_resolve_id(id), "expected a resolve stub id"); // allocate space for the code ResourceMark rm; + const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1000, 512); MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); @@ -2652,7 +2658,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // otherwise assume that stack unwinding will be initiated, so // caller saved registers were assumed volatile in the compiler. -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { + assert(is_throw_id(id), "expected a throw stub id"); + + const char* name = SharedRuntime::stub_name(id); + // Information about frame layout at time of blocking runtime call. // Note that we only have to preserve callee-saved registers since // the compilers are responsible for supplying a continuation point @@ -2759,7 +2769,8 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { int insts_size = 1024; int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id); + CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2779,7 +2790,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { oop_maps->add_gc_map(the_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; @@ -2797,7 +2808,8 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { int insts_size = 1024; int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id); + CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2816,7 +2828,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { oop_maps->add_gc_map(the_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 364ef948d91..9954c78ce1e 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2488,7 +2488,8 @@ void SharedRuntime::generate_deopt_blob() { // Allocate space for the code. ResourceMark rm; // Setup code generation tools. - CodeBuffer buffer("deopt_blob", 2048, 1024); + const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBuffer buffer(name, 2048, 1024); InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); Label exec_mode_initialized; OopMap* map = nullptr; @@ -2834,23 +2835,25 @@ void OptoRuntime::generate_uncommon_trap_blob() { // // Generate a special Compile2Runtime blob that saves all registers, // and setup oopmap. -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_polling_page_id(id), "expected a polling page stub id"); ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); OopMap* map; // Allocate space for the code. Setup code generation tools. - CodeBuffer buffer("handler_blob", 2048, 1024); + const char* name = SharedRuntime::stub_name(id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); unsigned int start_off = __ offset(); address call_pc = nullptr; int frame_size_in_bytes; - bool cause_return = (poll_type == POLL_AT_RETURN); + bool cause_return = (id == SharedStubId::polling_page_return_handler_id); // Make room for return address (or push it again) if (!cause_return) { __ z_lg(Z_R14, Address(Z_thread, JavaThread::saved_exception_pc_offset())); @@ -2935,12 +2938,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // but since this is generic code we don't know what they are and the caller // must do any gc of the args. // -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_resolve_id(id), "expected a resolve stub id"); // allocate space for the code ResourceMark rm; + const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1000, 512); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -3032,7 +3037,10 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // SharedRuntime.cpp requires that this code be generated into a // RuntimeStub. -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { + assert(is_throw_id(id), "expected a throw stub id"); + + const char* name = SharedRuntime::stub_name(id); int insts_size = 256; int locs_size = 0; diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 207d3fbb61e..345b779e809 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1405,12 +1405,6 @@ void Assembler::addb(Register dst, int imm8) { emit_arith_b(0x80, 0xC0, dst, imm8); } -void Assembler::addw(Register dst, Register src) { - emit_int8(0x66); - (void)prefix_and_encode(dst->encoding(), src->encoding()); - emit_arith(0x03, 0xC0, dst, src); -} - void Assembler::addw(Address dst, int imm16) { InstructionMark im(this); emit_int8(0x66); @@ -1632,11 +1626,6 @@ void Assembler::andb(Address dst, Register src) { emit_operand(src, dst, 0); } -void Assembler::andw(Register dst, Register src) { - (void)prefix_and_encode(dst->encoding(), src->encoding()); - emit_arith(0x23, 0xC0, dst, src); -} - void Assembler::andl(Address dst, int32_t imm32) { InstructionMark im(this); prefix(dst); @@ -4230,11 +4219,6 @@ void Assembler::notl(Register dst) { emit_int16((unsigned char)0xF7, (0xD0 | encode)); } -void Assembler::orw(Register dst, Register src) { - (void)prefix_and_encode(dst->encoding(), src->encoding()); - emit_arith(0x0B, 0xC0, dst, src); -} - void Assembler::orl(Address dst, int32_t imm32) { InstructionMark im(this); prefix(dst); @@ -6803,11 +6787,6 @@ void Assembler::xorb(Address dst, Register src) { emit_operand(src, dst, 0); } -void Assembler::xorw(Register dst, Register src) { - (void)prefix_and_encode(dst->encoding(), src->encoding()); - emit_arith(0x33, 0xC0, dst, src); -} - void Assembler::xorw(Register dst, Address src) { InstructionMark im(this); emit_int8(0x66); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 28457b7005b..9d1a12ca8e5 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1068,7 +1068,6 @@ class Assembler : public AbstractAssembler { void addb(Address dst, int imm8); void addb(Address dst, Register src); void addb(Register dst, int imm8); - void addw(Register dst, Register src); void addw(Address dst, int imm16); void addw(Address dst, Register src); @@ -1120,7 +1119,6 @@ class Assembler : public AbstractAssembler { void vaesdec(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vaesdeclast(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); - void andw(Register dst, Register src); void andb(Address dst, Register src); void andl(Address dst, int32_t imm32); @@ -1824,8 +1822,6 @@ class Assembler : public AbstractAssembler { #endif void btq(Register dst, Register src); - void orw(Register dst, Register src); - void orl(Address dst, int32_t imm32); void orl(Register dst, int32_t imm32); void orl(Register dst, Address src); @@ -2342,7 +2338,6 @@ class Assembler : public AbstractAssembler { void xorb(Address dst, Register src); void xorb(Register dst, Address src); - void xorw(Register dst, Register src); void xorw(Register dst, Address src); void xorq(Register dst, Address src); diff --git a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp index 41039e0cfd8..e4b25ce00d6 100644 --- a/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/downcallLinker_x86_64.cpp @@ -34,8 +34,8 @@ #define __ _masm-> -static const int native_invoker_code_base_size = 512; -static const int native_invoker_size_per_arg = 8; +static const int native_invoker_code_base_size = 256; +static const int native_invoker_size_per_arg = 16; RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature, int num_args, diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 273bbcc6525..c6ab00cc9ee 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -2062,7 +2062,8 @@ void SharedRuntime::generate_deopt_blob() { ResourceMark rm; // setup code generation tools // note: the buffer code size must account for StackShadowPages=50 - CodeBuffer buffer("deopt_blob", 1536, 1024); + const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBuffer buffer(name, 1536, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; OopMap* map = nullptr; @@ -2403,13 +2404,14 @@ void SharedRuntime::generate_deopt_blob() { // setup oopmap, and calls safepoint code to stop the compiled code for // a safepoint. // -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { // Account for thread arg in our frame const int additional_words = 1; int frame_size_in_words; assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_polling_page_id(id), "expected a polling page stub id"); ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); @@ -2417,14 +2419,15 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // allocate space for the code // setup code generation tools - CodeBuffer buffer("handler_blob", 2048, 1024); + const char* name = SharedRuntime::stub_name(id); + CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); const Register java_thread = rdi; // callee-saved for VC++ address start = __ pc(); address call_pc = nullptr; - bool cause_return = (poll_type == POLL_AT_RETURN); - bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); + bool cause_return = (id == SharedStubId::polling_page_return_handler_id); + bool save_vectors = (id == SharedStubId::polling_page_vectors_safepoint_handler_id); // If cause_return is true we are at a poll_return and there is // the return address on the stack to the caller on the nmethod @@ -2556,12 +2559,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // but since this is generic code we don't know what they are and the caller // must do any gc of the args. // -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_resolve_id(id), "expected a resolve stub id"); // allocate space for the code ResourceMark rm; + const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1000, 512); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -2662,7 +2667,10 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are // either at call sites or otherwise assume that stack unwinding will be initiated, // so caller saved registers were assumed volatile in the compiler. -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { + assert(is_throw_id(id), "expected a throw stub id"); + + const char* name = SharedRuntime::stub_name(id); // Information about frame layout at time of blocking runtime call. // Note that we only have to preserve callee-saved registers since @@ -2776,7 +2784,8 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { int insts_size = 1024; int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id); + CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2795,7 +2804,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { oop_maps->add_gc_map(the_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; @@ -2817,7 +2826,8 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { int insts_size = 1024; int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id); + CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2835,7 +2845,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { oop_maps->add_gc_map(the_pc - start, map); RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); return stub; diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 05ec85ef09a..4bd91f640fc 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2623,7 +2623,8 @@ void SharedRuntime::generate_deopt_blob() { pad += 512; // Increase the buffer size when compiling for JVMCI } #endif - CodeBuffer buffer("deopt_blob", 2560+pad, 1024); + const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBuffer buffer(name, 2560+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; OopMap* map = nullptr; @@ -2981,23 +2982,25 @@ void SharedRuntime::generate_deopt_blob() { // Generate a special Compile2Runtime blob that saves all registers, // and setup oopmap. // -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_polling_page_id(id), "expected a polling page stub id"); ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); OopMap* map; // Allocate space for the code. Setup code generation tools. - CodeBuffer buffer("handler_blob", 2348, 1024); + const char* name = SharedRuntime::stub_name(id); + CodeBuffer buffer(name, 2348, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); address start = __ pc(); address call_pc = nullptr; int frame_size_in_words; - bool cause_return = (poll_type == POLL_AT_RETURN); - bool save_wide_vectors = (poll_type == POLL_AT_VECTOR_LOOP); + bool cause_return = (id == SharedStubId::polling_page_return_handler_id); + bool save_wide_vectors = (id == SharedStubId::polling_page_vectors_safepoint_handler_id); // Make room for return address (or push it again) if (!cause_return) { @@ -3140,12 +3143,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // but since this is generic code we don't know what they are and the caller // must do any gc of the args. // -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); + assert(is_resolve_id(id), "expected a resolve stub id"); // allocate space for the code ResourceMark rm; + const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1552, 512); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -3232,7 +3237,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // AbstractMethodError on entry) are either at call sites or // otherwise assume that stack unwinding will be initiated, so // caller saved registers were assumed volatile in the compiler. -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { + assert(is_throw_id(id), "expected a throw stub id"); + + const char* name = SharedRuntime::stub_name(id); + // Information about frame layout at time of blocking runtime call. // Note that we only have to preserve callee-saved registers since // the compilers are responsible for supplying a continuation point @@ -3591,7 +3600,8 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { framesize // inclusive of return address }; - CodeBuffer code("jfr_write_checkpoint", 1024, 64); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_write_checkpoint_id); + CodeBuffer code(name, 1024, 64); MacroAssembler* masm = new MacroAssembler(&code); address start = __ pc(); @@ -3616,7 +3626,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { oop_maps->add_gc_map(frame_complete, map); RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), @@ -3635,7 +3645,8 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { framesize // inclusive of return address }; - CodeBuffer code("jfr_return_lease", 1024, 64); + const char* name = SharedRuntime::stub_name(SharedStubId::jfr_return_lease_id); + CodeBuffer code(name, 1024, 64); MacroAssembler* masm = new MacroAssembler(&code); address start = __ pc(); @@ -3657,7 +3668,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { oop_maps->add_gc_map(frame_complete, map); RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), + RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index 454f8e5f632..18ceb9514d3 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -105,15 +105,15 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob = generate_empty_deopt_blob(); } -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { +SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { return generate_empty_safepoint_blob(); } -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { +RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address destination) { return generate_empty_runtime_stub(); } -RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { +RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address runtime_entry) { return generate_empty_runtime_stub(); } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 1da0e44dbf4..d51499611a8 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -609,7 +609,7 @@ jlong CgroupSubsystem::memory_limit_in_bytes() { bool CgroupController::read_string(const char* filename, char* buf, size_t buf_size) { assert(buf != nullptr, "buffer must not be null"); assert(filename != nullptr, "filename must be given"); - char* s_path = subsystem_path(); + const char* s_path = subsystem_path(); if (s_path == nullptr) { log_debug(os, container)("read_string: subsystem path is null"); return false; @@ -679,7 +679,7 @@ bool CgroupController::read_numerical_key_value(const char* filename, const char assert(key != nullptr, "key must be given"); assert(result != nullptr, "result pointer must not be null"); assert(filename != nullptr, "file to search in must be given"); - char* s_path = subsystem_path(); + const char* s_path = subsystem_path(); if (s_path == nullptr) { log_debug(os, container)("read_numerical_key_value: subsystem path is null"); return false; diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index a964d8cdb80..40948dc5e28 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -103,9 +103,15 @@ } class CgroupController: public CHeapObj { + protected: + char* _cgroup_path; + char* _mount_point; public: - virtual char* subsystem_path() = 0; + virtual const char* subsystem_path() = 0; virtual bool is_read_only() = 0; + const char* cgroup_path() { return _cgroup_path; } + const char* mount_point() { return _mount_point; } + virtual bool needs_hierarchy_adjustment() { return false; } /* Read a numerical value as unsigned long * @@ -202,7 +208,12 @@ class CgroupCpuController: public CHeapObj { virtual int cpu_quota() = 0; virtual int cpu_period() = 0; virtual int cpu_shares() = 0; + virtual bool needs_hierarchy_adjustment() = 0; virtual bool is_read_only() = 0; + virtual const char* subsystem_path() = 0; + virtual void set_subsystem_path(const char* cgroup_path) = 0; + virtual const char* mount_point() = 0; + virtual const char* cgroup_path() = 0; }; // Pure virtual class representing version agnostic memory controllers @@ -217,9 +228,12 @@ class CgroupMemoryController: public CHeapObj { virtual jlong rss_usage_in_bytes() = 0; virtual jlong cache_usage_in_bytes() = 0; virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0; + virtual bool needs_hierarchy_adjustment() = 0; virtual bool is_read_only() = 0; - // SapMachine 2024-07-05: Vitals use subsystem path directly - virtual char* subsystem_path() = 0; + virtual const char* subsystem_path() = 0; + virtual void set_subsystem_path(const char* cgroup_path) = 0; + virtual const char* mount_point() = 0; + virtual const char* cgroup_path() = 0; }; class CgroupSubsystem: public CHeapObj { diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index 24046991905..bc0e018d6be 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -22,6 +22,7 @@ * */ +#include "os_linux.hpp" #include "cgroupUtil_linux.hpp" int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { @@ -46,3 +47,113 @@ int CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int host_cpus) { log_trace(os, container)("OSContainer::active_processor_count: %d", result); return result; } + +void CgroupUtil::adjust_controller(CgroupMemoryController* mem) { + if (!mem->needs_hierarchy_adjustment()) { + // nothing to do + return; + } + log_trace(os, container)("Adjusting controller path for memory: %s", mem->subsystem_path()); + assert(mem->cgroup_path() != nullptr, "invariant"); + char* orig = os::strdup(mem->cgroup_path()); + char* cg_path = os::strdup(orig); + char* last_slash; + assert(cg_path[0] == '/', "cgroup path must start with '/'"); + julong phys_mem = os::Linux::physical_memory(); + char* limit_cg_path = nullptr; + jlong limit = mem->read_memory_limit_in_bytes(phys_mem); + jlong lowest_limit = phys_mem; + while ((last_slash = strrchr(cg_path, '/')) != cg_path) { + *last_slash = '\0'; // strip path + // update to shortened path and try again + mem->set_subsystem_path(cg_path); + limit = mem->read_memory_limit_in_bytes(phys_mem); + if (limit >= 0 && limit < lowest_limit) { + lowest_limit = limit; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup(cg_path); + } + } + // need to check limit at mount point + mem->set_subsystem_path("/"); + limit = mem->read_memory_limit_in_bytes(phys_mem); + if (limit >= 0 && limit < lowest_limit) { + lowest_limit = limit; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup("/"); + } + assert(lowest_limit >= 0, "limit must be positive"); + if ((julong)lowest_limit != phys_mem) { + // we've found a lower limit anywhere in the hierarchy, + // set the path to the limit path + assert(limit_cg_path != nullptr, "limit path must be set"); + mem->set_subsystem_path(limit_cg_path); + log_trace(os, container)("Adjusted controller path for memory to: %s. " + "Lowest limit was: " JLONG_FORMAT, + mem->subsystem_path(), + lowest_limit); + } else { + log_trace(os, container)("No lower limit found for memory in hierarchy %s, " + "adjusting to original path %s", + mem->mount_point(), orig); + mem->set_subsystem_path(orig); + } + os::free(cg_path); + os::free(orig); + os::free(limit_cg_path); +} + +void CgroupUtil::adjust_controller(CgroupCpuController* cpu) { + if (!cpu->needs_hierarchy_adjustment()) { + // nothing to do + return; + } + log_trace(os, container)("Adjusting controller path for cpu: %s", cpu->subsystem_path()); + assert(cpu->cgroup_path() != nullptr, "invariant"); + char* orig = os::strdup(cpu->cgroup_path()); + char* cg_path = os::strdup(orig); + char* last_slash; + assert(cg_path[0] == '/', "cgroup path must start with '/'"); + int host_cpus = os::Linux::active_processor_count(); + int cpus = CgroupUtil::processor_count(cpu, host_cpus); + int lowest_limit = host_cpus; + char* limit_cg_path = nullptr; + while ((last_slash = strrchr(cg_path, '/')) != cg_path) { + *last_slash = '\0'; // strip path + // update to shortened path and try again + cpu->set_subsystem_path(cg_path); + cpus = CgroupUtil::processor_count(cpu, host_cpus); + if (cpus != host_cpus && cpus < lowest_limit) { + lowest_limit = cpus; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup(cg_path); + } + } + // need to check limit at mount point + cpu->set_subsystem_path("/"); + cpus = CgroupUtil::processor_count(cpu, host_cpus); + if (cpus != host_cpus && cpus < lowest_limit) { + lowest_limit = cpus; + os::free(limit_cg_path); // handles nullptr + limit_cg_path = os::strdup(cg_path); + } + assert(lowest_limit >= 0, "limit must be positive"); + if (lowest_limit != host_cpus) { + // we've found a lower limit anywhere in the hierarchy, + // set the path to the limit path + assert(limit_cg_path != nullptr, "limit path must be set"); + cpu->set_subsystem_path(limit_cg_path); + log_trace(os, container)("Adjusted controller path for cpu to: %s. " + "Lowest limit was: %d", + cpu->subsystem_path(), + lowest_limit); + } else { + log_trace(os, container)("No lower limit found for cpu in hierarchy %s, " + "adjusting to original path %s", + cpu->mount_point(), orig); + cpu->set_subsystem_path(orig); + } + os::free(cg_path); + os::free(orig); + os::free(limit_cg_path); +} diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp index fdcc4806c3b..19220af3177 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.hpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -32,6 +32,12 @@ class CgroupUtil: AllStatic { public: static int processor_count(CgroupCpuController* cpu, int host_cpus); + // Given a memory controller, adjust its path to a point in the hierarchy + // that represents the closest memory limit. + static void adjust_controller(CgroupMemoryController* m); + // Given a cpu controller, adjust its path to a point in the hierarchy + // that represents the closest cpu limit. + static void adjust_controller(CgroupCpuController* c); }; #endif // CGROUP_UTIL_LINUX_HPP diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index d7f9918afda..388ee5c6ea0 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -38,7 +38,15 @@ * Set directory to subsystem specific files based * on the contents of the mountinfo and cgroup files. */ -void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { +void CgroupV1Controller::set_subsystem_path(const char* cgroup_path) { + if (_cgroup_path != nullptr) { + os::free(_cgroup_path); + } + if (_path != nullptr) { + os::free(_path); + _path = nullptr; + } + _cgroup_path = os::strdup(cgroup_path); stringStream ss; if (_root != nullptr && cgroup_path != nullptr) { if (strcmp(_root, "/") == 0) { @@ -52,7 +60,7 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { ss.print_raw(_mount_point); _path = os::strdup(ss.base()); } else { - char *p = strstr(cgroup_path, _root); + char *p = strstr((char*)cgroup_path, _root); if (p != nullptr && p == _root) { if (strlen(cgroup_path) > strlen(_root)) { ss.print_raw(_mount_point); @@ -66,27 +74,15 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { } } -/* uses_mem_hierarchy - * - * Return whether or not hierarchical cgroup accounting is being - * done. - * - * return: - * A number > 0 if true, or - * OSCONTAINER_ERROR for not supported +/* + * The common case, containers, we have _root == _cgroup_path, and thus set the + * controller path to the _mount_point. This is where the limits are exposed in + * the cgroup pseudo filesystem (at the leaf) and adjustment of the path won't + * be needed for that reason. */ -jlong CgroupV1MemoryController::uses_mem_hierarchy() { - julong use_hierarchy; - CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.use_hierarchy", "Use Hierarchy", use_hierarchy); - return (jlong)use_hierarchy; -} - -void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { - reader()->set_subsystem_path(cgroup_path); - jlong hierarchy = uses_mem_hierarchy(); - if (hierarchy > 0) { - set_hierarchical(true); - } +bool CgroupV1Controller::needs_hierarchy_adjustment() { + assert(_cgroup_path != nullptr, "sanity"); + return strcmp(_root, _cgroup_path) != 0; } static inline @@ -115,20 +111,6 @@ jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) { julong memlimit; CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.limit_in_bytes", "Memory Limit", memlimit); if (memlimit >= phys_mem) { - log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); - if (is_hierarchical()) { - julong hier_memlimit; - bool is_ok = reader()->read_numerical_key_value("/memory.stat", "hierarchical_memory_limit", &hier_memlimit); - if (!is_ok) { - return OSCONTAINER_ERROR; - } - log_trace(os, container)("Hierarchical Memory Limit is: " JULONG_FORMAT, hier_memlimit); - if (hier_memlimit < phys_mem) { - verbose_log(hier_memlimit, phys_mem); - return (jlong)hier_memlimit; - } - log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); - } verbose_log(memlimit, phys_mem); return (jlong)-1; } else { @@ -150,26 +132,10 @@ jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) { * upper bound) */ jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) { - julong hier_memswlimit; julong memswlimit; CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); if (memswlimit >= host_total_memsw) { - log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); - if (is_hierarchical()) { - const char* matchline = "hierarchical_memsw_limit"; - bool is_ok = reader()->read_numerical_key_value("/memory.stat", - matchline, - &hier_memswlimit); - if (!is_ok) { - return OSCONTAINER_ERROR; - } - log_trace(os, container)("Hierarchical Memory and Swap Limit is: " JULONG_FORMAT, hier_memswlimit); - if (hier_memswlimit >= host_total_memsw) { - log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited"); - } else { - return (jlong)hier_memswlimit; - } - } + log_trace(os, container)("Memory and Swap Limit is: Unlimited"); return (jlong)-1; } else { return (jlong)memswlimit; @@ -233,6 +199,21 @@ jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { } } +// Constructor +CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset, + CgroupV1CpuController* cpu, + CgroupV1Controller* cpuacct, + CgroupV1Controller* pids, + CgroupV1MemoryController* memory) : + _cpuset(cpuset), + _cpuacct(cpuacct), + _pids(pids) { + CgroupUtil::adjust_controller(memory); + CgroupUtil::adjust_controller(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); +} + bool CgroupV1Subsystem::is_containerized() { // containerized iff all required controllers are mounted // read-only. See OSContainer::is_containerized() for diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 3463ae0ce83..0c191ab91c7 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -28,6 +28,7 @@ #include "runtime/os.hpp" #include "memory/allocation.hpp" #include "cgroupSubsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" // Cgroups version 1 specific implementation @@ -35,7 +36,6 @@ class CgroupV1Controller: public CgroupController { private: /* mountinfo contents */ char* _root; - char* _mount_point; bool _read_only; /* Constructed subsystem directory */ @@ -45,24 +45,27 @@ class CgroupV1Controller: public CgroupController { CgroupV1Controller(char *root, char *mountpoint, bool ro) : _root(os::strdup(root)), - _mount_point(os::strdup(mountpoint)), _read_only(ro), _path(nullptr) { + _cgroup_path = nullptr; + _mount_point = os::strdup(mountpoint); } // Shallow copy constructor CgroupV1Controller(const CgroupV1Controller& o) : _root(o._root), - _mount_point(o._mount_point), _read_only(o._read_only), _path(o._path) { + _cgroup_path = o._cgroup_path; + _mount_point = o._mount_point; } ~CgroupV1Controller() { // At least one subsystem controller exists with paths to malloc'd path // names } - void set_subsystem_path(char *cgroup_path); - char *subsystem_path() override { return _path; } + void set_subsystem_path(const char *cgroup_path); + const char* subsystem_path() override { return _path; } bool is_read_only() override { return _read_only; } + bool needs_hierarchy_adjustment() override; }; class CgroupV1MemoryController final : public CgroupMemoryController { @@ -71,8 +74,9 @@ class CgroupV1MemoryController final : public CgroupMemoryController { CgroupV1Controller _reader; CgroupV1Controller* reader() { return &_reader; } public: - bool is_hierarchical() { return _uses_mem_hierarchy; } - void set_subsystem_path(char *cgroup_path); + void set_subsystem_path(const char *cgroup_path) override { + reader()->set_subsystem_path(cgroup_path); + } jlong read_memory_limit_in_bytes(julong upper_bound) override; jlong memory_usage_in_bytes() override; jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override; @@ -85,27 +89,22 @@ class CgroupV1MemoryController final : public CgroupMemoryController { jlong kernel_memory_limit_in_bytes(julong host_mem); jlong kernel_memory_max_usage_in_bytes(); void print_version_specific_info(outputStream* st, julong host_mem) override; + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } bool is_read_only() override { return reader()->is_read_only(); } - // SapMachine 2024-07-05: Vitals use subsystem path directly - virtual char* subsystem_path() override { - return reader()->subsystem_path(); - } + const char* subsystem_path() override { return reader()->subsystem_path(); } + const char* mount_point() override { return reader()->mount_point(); } + const char* cgroup_path() override { return reader()->cgroup_path(); } private: - /* Some container runtimes set limits via cgroup - * hierarchy. If set to true consider also memory.stat - * file if everything else seems unlimited */ - bool _uses_mem_hierarchy; - jlong uses_mem_hierarchy(); - void set_hierarchical(bool value) { _uses_mem_hierarchy = value; } jlong read_mem_swappiness(); jlong read_mem_swap(julong host_total_memsw); public: CgroupV1MemoryController(const CgroupV1Controller& reader) - : _reader(reader), - _uses_mem_hierarchy(false) { + : _reader(reader) { } }; @@ -119,12 +118,22 @@ class CgroupV1CpuController final : public CgroupCpuController { int cpu_quota() override; int cpu_period() override; int cpu_shares() override; - void set_subsystem_path(char *cgroup_path) { + void set_subsystem_path(const char *cgroup_path) override { reader()->set_subsystem_path(cgroup_path); } bool is_read_only() override { return reader()->is_read_only(); } + const char* subsystem_path() override { + return reader()->subsystem_path(); + } + const char* mount_point() override { + return reader()->mount_point(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + const char* cgroup_path() override { return reader()->cgroup_path(); } public: CgroupV1CpuController(const CgroupV1Controller& reader) : _reader(reader) { @@ -134,6 +143,12 @@ class CgroupV1CpuController final : public CgroupCpuController { class CgroupV1Subsystem: public CgroupSubsystem { public: + CgroupV1Subsystem(CgroupV1Controller* cpuset, + CgroupV1CpuController* cpu, + CgroupV1Controller* cpuacct, + CgroupV1Controller* pids, + CgroupV1MemoryController* memory); + jlong kernel_memory_usage_in_bytes(); jlong kernel_memory_limit_in_bytes(); jlong kernel_memory_max_usage_in_bytes(); @@ -159,18 +174,6 @@ class CgroupV1Subsystem: public CgroupSubsystem { CgroupV1Controller* _cpuacct = nullptr; CgroupV1Controller* _pids = nullptr; - public: - CgroupV1Subsystem(CgroupV1Controller* cpuset, - CgroupV1CpuController* cpu, - CgroupV1Controller* cpuacct, - CgroupV1Controller* pids, - CgroupV1MemoryController* memory) : - _memory(new CachingCgroupController(memory)), - _cpuset(cpuset), - _cpu(new CachingCgroupController(cpu)), - _cpuacct(cpuacct), - _pids(pids) { - } }; #endif // CGROUP_V1_SUBSYSTEM_LINUX_HPP diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 8f7e12d0954..62e8cac3a62 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -25,6 +25,22 @@ #include "cgroupV2Subsystem_linux.hpp" #include "cgroupUtil_linux.hpp" +// Constructor +CgroupV2Controller::CgroupV2Controller(char* mount_path, + char *cgroup_path, + bool ro) : _read_only(ro), + _path(construct_path(mount_path, cgroup_path)) { + _cgroup_path = os::strdup(cgroup_path); + _mount_point = os::strdup(mount_path); +} +// Shallow copy constructor +CgroupV2Controller::CgroupV2Controller(const CgroupV2Controller& o) : + _read_only(o._read_only), + _path(o._path) { + _cgroup_path = o._cgroup_path; + _mount_point = o._mount_point; +} + /* cpu_shares * * Return the amount of cpu shares available to the process @@ -95,6 +111,17 @@ int CgroupV2CpuController::cpu_quota() { return limit; } +// Constructor +CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory, + CgroupV2CpuController* cpu, + CgroupV2Controller unified) : + _unified(unified) { + CgroupUtil::adjust_controller(memory); + CgroupUtil::adjust_controller(cpu); + _memory = new CachingCgroupController(memory); + _cpu = new CachingCgroupController(cpu); +} + bool CgroupV2Subsystem::is_containerized() { return _unified.is_read_only() && _memory->controller()->is_read_only() && @@ -264,6 +291,18 @@ jlong memory_swap_limit_value(CgroupV2Controller* ctrl) { return swap_limit; } +void CgroupV2Controller::set_subsystem_path(const char* cgroup_path) { + if (_path != nullptr) { + os::free(_path); + } + _path = construct_path(_mount_point, cgroup_path); +} + +// For cgv2 we only need hierarchy walk if the cgroup path isn't '/' (root) +bool CgroupV2Controller::needs_hierarchy_adjustment() { + return strcmp(_cgroup_path, "/") != 0; +} + void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { jlong swap_current = memory_swap_current_value(reader()); jlong swap_limit = memory_swap_limit_value(reader()); @@ -272,7 +311,7 @@ void CgroupV2MemoryController::print_version_specific_info(outputStream* st, jul OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit_in_bytes"); } -char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) { +char* CgroupV2Controller::construct_path(char* mount_path, const char* cgroup_path) { stringStream ss; ss.print_raw(mount_path); if (strcmp(cgroup_path, "/") != 0) { diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 0331bcec4f8..527573644a8 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -26,39 +26,28 @@ #define CGROUP_V2_SUBSYSTEM_LINUX_HPP #include "cgroupSubsystem_linux.hpp" +#include "cgroupUtil_linux.hpp" class CgroupV2Controller: public CgroupController { private: - /* the mount path of the cgroup v2 hierarchy */ - char *_mount_path; - /* The cgroup path for the controller */ - char *_cgroup_path; bool _read_only; /* Constructed full path to the subsystem directory */ char *_path; - static char* construct_path(char* mount_path, char *cgroup_path); + static char* construct_path(char* mount_path, const char *cgroup_path); public: - CgroupV2Controller(char* mount_path, - char *cgroup_path, - bool ro) : _mount_path(os::strdup(mount_path)), - _cgroup_path(os::strdup(cgroup_path)), - _read_only(ro), - _path(construct_path(mount_path, cgroup_path)) { - } + CgroupV2Controller(char* mount_path, char *cgroup_path, bool ro); // Shallow copy constructor - CgroupV2Controller(const CgroupV2Controller& o) : - _mount_path(o._mount_path), - _cgroup_path(o._cgroup_path), - _read_only(o._read_only), - _path(o._path) { - } + CgroupV2Controller(const CgroupV2Controller& o); ~CgroupV2Controller() { // At least one controller exists with references to the paths } - char *subsystem_path() override { return _path; } + const char* subsystem_path() override { return _path; } + bool needs_hierarchy_adjustment() override; + // Allow for optional updates of the subsystem path + void set_subsystem_path(const char* cgroup_path); bool is_read_only() override { return _read_only; } }; @@ -75,6 +64,17 @@ class CgroupV2CpuController: public CgroupCpuController { bool is_read_only() override { return reader()->is_read_only(); } + const char* subsystem_path() { + return reader()->subsystem_path(); + } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + void set_subsystem_path(const char* cgroup_path) { + reader()->set_subsystem_path(cgroup_path); + } + const char* mount_point() { return reader()->mount_point(); } + const char* cgroup_path() override { return reader()->cgroup_path(); } }; class CgroupV2MemoryController final: public CgroupMemoryController { @@ -97,10 +97,17 @@ class CgroupV2MemoryController final: public CgroupMemoryController { bool is_read_only() override { return reader()->is_read_only(); } - // SapMachine 2024-07-05: Vitals use subsystem path directly - virtual char* subsystem_path() override { + const char* subsystem_path() { return reader()->subsystem_path(); } + bool needs_hierarchy_adjustment() override { + return reader()->needs_hierarchy_adjustment(); + } + void set_subsystem_path(const char* cgroup_path) { + reader()->set_subsystem_path(cgroup_path); + } + const char* mount_point() { return reader()->mount_point(); } + const char* cgroup_path() override { return reader()->cgroup_path(); } }; class CgroupV2Subsystem: public CgroupSubsystem { @@ -114,13 +121,9 @@ class CgroupV2Subsystem: public CgroupSubsystem { CgroupV2Controller* unified() { return &_unified; } public: - CgroupV2Subsystem(CgroupV2MemoryController* memory, + CgroupV2Subsystem(CgroupV2MemoryController * memory, CgroupV2CpuController* cpu, - CgroupV2Controller unified) : - _unified(unified), - _memory(new CachingCgroupController(memory)), - _cpu(new CachingCgroupController(cpu)) { - } + CgroupV2Controller unified); char * cpu_cpuset_cpus() override; char * cpu_cpuset_memory_nodes() override; diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 1d1d9d3e1a4..a1e0a78837f 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -5741,11 +5741,23 @@ void Parker::unpark() { SetEvent(_ParkHandle); } +// Platform Mutex/Monitor implementation + +PlatformMutex::PlatformMutex() { + InitializeCriticalSection(&_mutex); +} + PlatformMutex::~PlatformMutex() { DeleteCriticalSection(&_mutex); } -// Platform Monitor implementation +PlatformMonitor::PlatformMonitor() { + InitializeConditionVariable(&_cond); +} + +PlatformMonitor::~PlatformMonitor() { + // There is no DeleteConditionVariable API +} // Must already be locked int PlatformMonitor::wait(uint64_t millis) { diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp index bb2da39d422..e9b30a33dfd 100644 --- a/src/hotspot/os/windows/os_windows.inline.hpp +++ b/src/hotspot/os/windows/os_windows.inline.hpp @@ -49,30 +49,23 @@ inline void os::map_stack_shadow_pages(address sp) { // If we decrement stack pointer more than one page // the OS may not map an intervening page into our space // and may fault on a memory access to interior of our frame. + address original_sp = sp; const size_t page_size = os::vm_page_size(); const size_t n_pages = StackOverflow::stack_shadow_zone_size() / page_size; for (size_t pages = 1; pages <= n_pages; pages++) { sp -= page_size; *sp = 0; } + StackOverflow* state = JavaThread::current()->stack_overflow_state(); + assert(original_sp > state->shadow_zone_safe_limit(), "original_sp=" INTPTR_FORMAT ", " + "shadow_zone_safe_limit=" INTPTR_FORMAT, p2i(original_sp), p2i(state->shadow_zone_safe_limit())); + state->set_shadow_zone_growth_watermark(original_sp); } inline bool os::numa_has_group_homing() { return false; } // Platform Mutex/Monitor implementation -inline PlatformMutex::PlatformMutex() { - InitializeCriticalSection(&_mutex); -} - -inline PlatformMonitor::PlatformMonitor() { - InitializeConditionVariable(&_cond); -} - -inline PlatformMonitor::~PlatformMonitor() { - // There is no DeleteConditionVariable API -} - inline void PlatformMutex::lock() { EnterCriticalSection(&_mutex); } diff --git a/src/hotspot/share/adlc/adlArena.cpp b/src/hotspot/share/adlc/adlArena.cpp index d29a255a905..d5a1dd500fa 100644 --- a/src/hotspot/share/adlc/adlArena.cpp +++ b/src/hotspot/share/adlc/adlArena.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -45,6 +45,7 @@ void* AdlReAllocateHeap(void* old_ptr, size_t size) { } void* AdlChunk::operator new(size_t requested_size, size_t length) throw() { + assert(requested_size <= SIZE_MAX - length, "overflow"); return AdlCHeapObj::operator new(requested_size + length); } @@ -129,6 +130,7 @@ void* AdlArena::grow( size_t x ) { //------------------------------calloc----------------------------------------- // Allocate zeroed storage in AdlArena void *AdlArena::Acalloc( size_t items, size_t x ) { + assert(items <= SIZE_MAX / x, "overflow"); size_t z = items*x; // Total size needed void *ptr = Amalloc(z); // Get space memset( ptr, 0, z ); // Zap space @@ -136,21 +138,26 @@ void *AdlArena::Acalloc( size_t items, size_t x ) { } //------------------------------realloc---------------------------------------- +static size_t pointer_delta(const void *left, const void *right) { + assert(left >= right, "pointer delta underflow"); + return (uintptr_t)left - (uintptr_t)right; +} + // Reallocate storage in AdlArena. void *AdlArena::Arealloc( void *old_ptr, size_t old_size, size_t new_size ) { char *c_old = (char*)old_ptr; // Handy name - // Stupid fast special case - if( new_size <= old_size ) { // Shrink in-place - if( c_old+old_size == _hwm) // Attempt to free the excess bytes - _hwm = c_old+new_size; // Adjust hwm - return c_old; - } - // See if we can resize in-place - if( (c_old+old_size == _hwm) && // Adjusting recent thing - (c_old+new_size <= _max) ) { // Still fits where it sits - _hwm = c_old+new_size; // Adjust hwm - return c_old; // Return old pointer + // Reallocating the latest allocation? + if (c_old + old_size == _hwm) { + assert(_chunk->bottom() <= c_old, "invariant"); + + // Reallocate in place if it fits. Also handles shrinking + if (pointer_delta(_max, c_old) >= new_size) { + _hwm = c_old + new_size; + return c_old; + } + } else if (new_size <= old_size) { // Shrink in place + return c_old; } // Oops, got to relocate guts diff --git a/src/hotspot/share/adlc/adlArena.hpp b/src/hotspot/share/adlc/adlArena.hpp index 254f414f707..2e8d8ae8ae2 100644 --- a/src/hotspot/share/adlc/adlArena.hpp +++ b/src/hotspot/share/adlc/adlArena.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -105,8 +105,10 @@ class AdlArena: public AdlCHeapObj { // Fast allocate in the arena. Common case is: pointer test + increment. void* Amalloc(size_t x) { #ifdef _LP64 + assert(x <= SIZE_MAX - (8-1), "overflow"); x = (x + (8-1)) & ((unsigned)(-8)); #else + assert(x <= SIZE_MAX - (4-1), "overflow"); x = (x + (4-1)) & ((unsigned)(-4)); #endif if (_hwm + x > _max) { diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 46421ccc90c..60fed287df5 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -1352,105 +1352,16 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, } -// Field allocation types. Used for computing field offsets. - -enum FieldAllocationType { - STATIC_OOP, // Oops - STATIC_BYTE, // Boolean, Byte, char - STATIC_SHORT, // shorts - STATIC_WORD, // ints - STATIC_DOUBLE, // aligned long or double - NONSTATIC_OOP, - NONSTATIC_BYTE, - NONSTATIC_SHORT, - NONSTATIC_WORD, - NONSTATIC_DOUBLE, - MAX_FIELD_ALLOCATION_TYPE, - BAD_ALLOCATION_TYPE = -1 -}; - -static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = { - BAD_ALLOCATION_TYPE, // 0 - BAD_ALLOCATION_TYPE, // 1 - BAD_ALLOCATION_TYPE, // 2 - BAD_ALLOCATION_TYPE, // 3 - NONSTATIC_BYTE , // T_BOOLEAN = 4, - NONSTATIC_SHORT, // T_CHAR = 5, - NONSTATIC_WORD, // T_FLOAT = 6, - NONSTATIC_DOUBLE, // T_DOUBLE = 7, - NONSTATIC_BYTE, // T_BYTE = 8, - NONSTATIC_SHORT, // T_SHORT = 9, - NONSTATIC_WORD, // T_INT = 10, - NONSTATIC_DOUBLE, // T_LONG = 11, - NONSTATIC_OOP, // T_OBJECT = 12, - NONSTATIC_OOP, // T_ARRAY = 13, - BAD_ALLOCATION_TYPE, // T_VOID = 14, - BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, - BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, - BAD_ALLOCATION_TYPE, // T_METADATA = 17, - BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, - BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, - BAD_ALLOCATION_TYPE, // 0 - BAD_ALLOCATION_TYPE, // 1 - BAD_ALLOCATION_TYPE, // 2 - BAD_ALLOCATION_TYPE, // 3 - STATIC_BYTE , // T_BOOLEAN = 4, - STATIC_SHORT, // T_CHAR = 5, - STATIC_WORD, // T_FLOAT = 6, - STATIC_DOUBLE, // T_DOUBLE = 7, - STATIC_BYTE, // T_BYTE = 8, - STATIC_SHORT, // T_SHORT = 9, - STATIC_WORD, // T_INT = 10, - STATIC_DOUBLE, // T_LONG = 11, - STATIC_OOP, // T_OBJECT = 12, - STATIC_OOP, // T_ARRAY = 13, - BAD_ALLOCATION_TYPE, // T_VOID = 14, - BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, - BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, - BAD_ALLOCATION_TYPE, // T_METADATA = 17, - BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, - BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, -}; - -static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) { - assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values"); - FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)]; - assert(result != BAD_ALLOCATION_TYPE, "bad type"); - return result; -} - -class ClassFileParser::FieldAllocationCount : public ResourceObj { - public: - u2 count[MAX_FIELD_ALLOCATION_TYPE]; - - FieldAllocationCount() { - for (int i = 0; i < MAX_FIELD_ALLOCATION_TYPE; i++) { - count[i] = 0; - } - } - - void update(bool is_static, BasicType type) { - FieldAllocationType atype = basic_type_to_atype(is_static, type); - if (atype != BAD_ALLOCATION_TYPE) { - // Make sure there is no overflow with injected fields. - assert(count[atype] < 0xFFFF, "More than 65535 fields"); - count[atype]++; - } - } -}; - // Side-effects: populates the _fields, _fields_annotations, // _fields_type_annotations fields void ClassFileParser::parse_fields(const ClassFileStream* const cfs, bool is_interface, - FieldAllocationCount* const fac, ConstantPool* cp, const int cp_size, u2* const java_fields_count_ptr, TRAPS) { assert(cfs != nullptr, "invariant"); - assert(fac != nullptr, "invariant"); assert(cp != nullptr, "invariant"); assert(java_fields_count_ptr != nullptr, "invariant"); @@ -1544,8 +1455,10 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const BasicType type = cp->basic_type_for_signature_at(signature_index); - // Update FieldAllocationCount for this kind of field - fac->update(is_static, type); + // Update number of static oop fields. + if (is_static && is_reference_type(type)) { + _static_oop_count++; + } FieldInfo fi(access_flags, name_index, signature_index, constantvalue_index, fieldFlags); fi.set_index(n); @@ -1590,10 +1503,6 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, FieldInfo fi(aflags, (u2)(injected[n].name_index), (u2)(injected[n].signature_index), 0, fflags); fi.set_index(index); _temp_field_info->append(fi); - - // Update FieldAllocationCount for this kind of field - const BasicType type = Signature::basic_type(injected[n].signature()); - fac->update(false, type); index++; } } @@ -5117,8 +5026,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // Not yet: supers are done below to support the new subtype-checking fields ik->set_nonstatic_field_size(_field_info->_nonstatic_field_size); ik->set_has_nonstatic_fields(_field_info->_has_nonstatic_fields); - assert(_fac != nullptr, "invariant"); - ik->set_static_oop_field_count(_fac->count[STATIC_OOP]); + ik->set_static_oop_field_count(_static_oop_count); // this transfers ownership of a lot of arrays from // the parser onto the InstanceKlass* @@ -5360,6 +5268,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _is_hidden(cl_info->is_hidden()), _can_access_vm_annotations(cl_info->can_access_vm_annotations()), _orig_cp_size(0), + _static_oop_count(0), _super_klass(), _cp(nullptr), _fieldinfo_stream(nullptr), @@ -5380,7 +5289,6 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _klass(nullptr), _klass_to_deallocate(nullptr), _parsed_annotations(nullptr), - _fac(nullptr), _field_info(nullptr), _temp_field_info(nullptr), _method_ordering(nullptr), @@ -5706,10 +5614,8 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, assert(_local_interfaces != nullptr, "invariant"); // Fields (offsets are filled in later) - _fac = new FieldAllocationCount(); parse_fields(stream, _access_flags.is_interface(), - _fac, cp, cp_size, &_java_fields_count, @@ -5867,7 +5773,6 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st _itable_size = _access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); - assert(_fac != nullptr, "invariant"); assert(_parsed_annotations != nullptr, "invariant"); _field_info = new FieldLayoutInfo(); diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 69d1f357ca5..d32dd6d5f78 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -86,7 +86,6 @@ class ClassFileParser { friend class FieldLayout; class ClassAnnotationCollector; - class FieldAllocationCount; class FieldAnnotationCollector; public: @@ -116,6 +115,7 @@ class ClassFileParser { const bool _is_hidden; const bool _can_access_vm_annotations; int _orig_cp_size; + unsigned int _static_oop_count; // Metadata created before the instance klass is created. Must be deallocated // if not transferred to the InstanceKlass upon successful class loading @@ -141,7 +141,6 @@ class ClassFileParser { InstanceKlass* _klass_to_deallocate; // an InstanceKlass* to be destroyed ClassAnnotationCollector* _parsed_annotations; - FieldAllocationCount* _fac; FieldLayoutInfo* _field_info; GrowableArray* _temp_field_info; const intArray* _method_ordering; @@ -260,7 +259,6 @@ class ClassFileParser { void parse_fields(const ClassFileStream* const cfs, bool is_interface, - FieldAllocationCount* const fac, ConstantPool* cp, const int cp_size, u2* const java_fields_count_ptr, @@ -549,6 +547,7 @@ class ClassFileParser { bool is_hidden() const { return _is_hidden; } bool is_interface() const { return _access_flags.is_interface(); } + bool is_abstract() const { return _access_flags.is_abstract(); } ClassLoaderData* loader_data() const { return _loader_data; } const Symbol* class_name() const { return _class_name; } diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index 19306a2a9db..50453cee61d 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -174,7 +174,8 @@ class SymbolTableConfig : public AllStatic { log_trace_symboltable_helper(&value, "Freeing permanent symbol"); size_t alloc_size = SymbolTableHash::get_dynamic_node_size(value.byte_size()); if (!SymbolTable::arena()->Afree(memory, alloc_size)) { - log_trace_symboltable_helper(&value, "Leaked permanent symbol"); + // Can't access the symbol after Afree, but we just printed it above. + NOT_PRODUCT(log_trace(symboltable)(" - Leaked permanent symbol");) } } SymbolTable::item_removed(); diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 26ae5f7df59..8ecd9e21537 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -595,6 +595,7 @@ class UpcallLinker; // A (Panama) upcall stub. Not used by JNI. class UpcallStub: public RuntimeBlob { + friend class VMStructs; friend class UpcallLinker; private: jobject _receiver; diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 4c66c526151..5789b44e618 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -172,7 +172,6 @@ class PrepareRegionsClosure : public G1HeapRegionClosure { bool do_heap_region(G1HeapRegion* hr) { hr->prepare_for_full_gc(); - hr->uninstall_group_cardset(); G1CollectedHeap::heap()->prepare_region_for_full_compaction(hr); _collector->before_marking_update_attribute_table(hr); return false; diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp index 4c93aca8492..910f878ef7f 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp @@ -37,6 +37,8 @@ void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(G1 } bool G1FullGCResetMetadataTask::G1ResetMetadataClosure::do_heap_region(G1HeapRegion* hr) { + hr->uninstall_group_cardset(); + uint const region_idx = hr->hrm_index(); if (!_collector->is_compaction_target(region_idx)) { assert(!hr->is_free(), "all free regions should be compaction targets"); diff --git a/src/hotspot/share/gc/z/zForwarding.cpp b/src/hotspot/share/gc/z/zForwarding.cpp index d8a3913806c..4df6e9a2d81 100644 --- a/src/hotspot/share/gc/z/zForwarding.cpp +++ b/src/hotspot/share/gc/z/zForwarding.cpp @@ -73,7 +73,7 @@ void ZForwarding::in_place_relocation_finish() { if (_from_age == ZPageAge::old || _to_age != ZPageAge::old) { // Only do this for non-promoted pages, that still need to reset live map. // Done with iterating over the "from-page" view, so can now drop the _livemap. - _page->finalize_reset_for_in_place_relocation(); + _page->reset_livemap(); } // Disable relaxed ZHeap::is_in checks diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp index 27a5965700f..bf6dc98fc72 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp @@ -25,6 +25,7 @@ #include "gc/z/zGlobals.hpp" #include "gc/z/zHeap.inline.hpp" #include "gc/z/zHeuristics.hpp" +#include "gc/z/zLock.inline.hpp" #include "gc/z/zObjectAllocator.hpp" #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageTable.inline.hpp" @@ -45,8 +46,9 @@ ZObjectAllocator::ZObjectAllocator(ZPageAge age) _use_per_cpu_shared_small_pages(ZHeuristics::use_per_cpu_shared_small_pages()), _used(0), _undone(0), + _shared_small_page(nullptr), _shared_medium_page(nullptr), - _shared_small_page(nullptr) {} + _medium_page_alloc_lock() {} ZPage** ZObjectAllocator::shared_small_page_addr() { return _use_per_cpu_shared_small_pages ? _shared_small_page.addr() : _shared_small_page.addr(0); @@ -126,6 +128,42 @@ zaddress ZObjectAllocator::alloc_object_in_shared_page(ZPage** shared_page, return addr; } +zaddress ZObjectAllocator::alloc_object_in_medium_page(size_t size, + ZAllocationFlags flags) { + zaddress addr = zaddress::null; + ZPage** shared_medium_page = _shared_medium_page.addr(); + ZPage* page = Atomic::load_acquire(shared_medium_page); + + if (page != nullptr) { + addr = page->alloc_object_atomic(size); + } + + if (is_null(addr)) { + // When a new medium page is required, we synchronize the allocation + // of the new page using a lock. This is to avoid having multiple + // threads requesting a medium page from the page cache when we know + // only one of the will succeed in installing the page at this layer. + ZLocker locker(&_medium_page_alloc_lock); + + // When holding the lock we can't allow the page allocator to stall, + // which in the common case it won't. The page allocation is thus done + // in a non-blocking fashion and only if this fails we below (while not + // holding the lock) do the blocking page allocation. + ZAllocationFlags non_blocking_flags = flags; + non_blocking_flags.set_non_blocking(); + + addr = alloc_object_in_shared_page(shared_medium_page, ZPageType::medium, ZPageSizeMedium, size, non_blocking_flags); + } + + if (is_null(addr) && !flags.non_blocking()) { + // The above allocation attempts failed and this allocation should stall + // until memory is available. Redo the allocation with blocking enabled. + addr = alloc_object_in_shared_page(shared_medium_page, ZPageType::medium, ZPageSizeMedium, size, flags); + } + + return addr; +} + zaddress ZObjectAllocator::alloc_large_object(size_t size, ZAllocationFlags flags) { zaddress addr = zaddress::null; @@ -141,7 +179,7 @@ zaddress ZObjectAllocator::alloc_large_object(size_t size, ZAllocationFlags flag } zaddress ZObjectAllocator::alloc_medium_object(size_t size, ZAllocationFlags flags) { - return alloc_object_in_shared_page(_shared_medium_page.addr(), ZPageType::medium, ZPageSizeMedium, size, flags); + return alloc_object_in_medium_page(size, flags); } zaddress ZObjectAllocator::alloc_small_object(size_t size, ZAllocationFlags flags) { diff --git a/src/hotspot/share/gc/z/zObjectAllocator.hpp b/src/hotspot/share/gc/z/zObjectAllocator.hpp index 8aa185646fa..5377972b7ba 100644 --- a/src/hotspot/share/gc/z/zObjectAllocator.hpp +++ b/src/hotspot/share/gc/z/zObjectAllocator.hpp @@ -26,6 +26,7 @@ #include "gc/z/zAddress.hpp" #include "gc/z/zAllocationFlags.hpp" +#include "gc/z/zLock.hpp" #include "gc/z/zPageAge.hpp" #include "gc/z/zPageType.hpp" #include "gc/z/zValue.hpp" @@ -39,8 +40,9 @@ class ZObjectAllocator { const bool _use_per_cpu_shared_small_pages; ZPerCPU _used; ZPerCPU _undone; - ZContended _shared_medium_page; ZPerCPU _shared_small_page; + ZContended _shared_medium_page; + ZLock _medium_page_alloc_lock; ZPage** shared_small_page_addr(); ZPage* const* shared_small_page_addr() const; @@ -56,6 +58,9 @@ class ZObjectAllocator { size_t size, ZAllocationFlags flags); + zaddress alloc_object_in_medium_page(size_t size, + ZAllocationFlags flags); + zaddress alloc_large_object(size_t size, ZAllocationFlags flags); zaddress alloc_medium_object(size_t size, ZAllocationFlags flags); zaddress alloc_small_object(size_t size, ZAllocationFlags flags); diff --git a/src/hotspot/share/gc/z/zPage.cpp b/src/hotspot/share/gc/z/zPage.cpp index bfeda56de37..dc40c5367c1 100644 --- a/src/hotspot/share/gc/z/zPage.cpp +++ b/src/hotspot/share/gc/z/zPage.cpp @@ -57,14 +57,9 @@ ZPage::ZPage(ZPageType type, const ZVirtualMemory& vmem, const ZPhysicalMemory& } ZPage* ZPage::clone_limited() const { - // Only copy type and memory layouts. Let the rest be lazily reconstructed when needed. - return new ZPage(_type, _virtual, _physical); -} - -ZPage* ZPage::clone_limited_promote_flipped() const { + // Only copy type and memory layouts, and also update _top. Let the rest be + // lazily reconstructed when needed. ZPage* const page = new ZPage(_type, _virtual, _physical); - - // The page is still filled with the same objects, need to retain the top pointer. page->_top = _top; return page; @@ -83,58 +78,30 @@ void ZPage::reset_seqnum() { Atomic::store(&_seqnum_other, ZGeneration::generation(_generation_id == ZGenerationId::young ? ZGenerationId::old : ZGenerationId::young)->seqnum()); } -void ZPage::remset_clear() { - _remembered_set.clear_all(); -} - -void ZPage::verify_remset_after_reset(ZPageAge prev_age, ZPageResetType type) { - // Young-to-old reset - if (prev_age != ZPageAge::old) { - verify_remset_cleared_previous(); - verify_remset_cleared_current(); - return; - } +void ZPage::remset_initialize() { + // Remsets should only be initialized once and only for old pages. + assert(!_remembered_set.is_initialized(), "Should not be initialized"); + assert(is_old(), "Only old pages need a remset"); - // Old-to-old reset - switch (type) { - case ZPageResetType::InPlaceRelocation: - // Relocation failed and page is being compacted in-place. - // The remset bits are flipped each young mark start, so - // the verification code below needs to use the right remset. - if (ZGeneration::old()->active_remset_is_current()) { - verify_remset_cleared_previous(); - } else { - verify_remset_cleared_current(); - } - break; + _remembered_set.initialize(size()); +} - case ZPageResetType::FlipAging: - fatal("Should not have called this for old-to-old flipping"); - break; +void ZPage::remset_initialize_or_verify_cleared() { + assert(is_old(), "Only old pages need a remset"); - case ZPageResetType::Allocation: - verify_remset_cleared_previous(); + if (_remembered_set.is_initialized()) { verify_remset_cleared_current(); - break; - }; -} - -void ZPage::reset_remembered_set() { - if (is_young()) { - // Remset not needed - return; + verify_remset_cleared_previous(); + } else { + remset_initialize(); } +} - // Clearing of remsets is done when freeing a page, so this code only - // needs to ensure the remset is initialized the first time a page - // becomes old. - if (!_remembered_set.is_initialized()) { - _remembered_set.initialize(size()); - } +void ZPage::remset_clear() { + _remembered_set.clear_all(); } -void ZPage::reset(ZPageAge age, ZPageResetType type) { - const ZPageAge prev_age = _age; +void ZPage::reset(ZPageAge age) { _age = age; _last_used = 0; @@ -143,27 +110,16 @@ void ZPage::reset(ZPageAge age, ZPageResetType type) { : ZGenerationId::young; reset_seqnum(); - - // Flip aged pages are still filled with the same objects, need to retain the top pointer. - if (type != ZPageResetType::FlipAging) { - _top = to_zoffset_end(start()); - } - - reset_remembered_set(); - verify_remset_after_reset(prev_age, type); - - if (type != ZPageResetType::InPlaceRelocation || (prev_age != ZPageAge::old && age == ZPageAge::old)) { - // Promoted in-place relocations reset the live map, - // because they clone the page. - _livemap.reset(); - } } -void ZPage::finalize_reset_for_in_place_relocation() { - // Now we're done iterating over the livemaps +void ZPage::reset_livemap() { _livemap.reset(); } +void ZPage::reset_top_for_allocation() { + _top = to_zoffset_end(start()); +} + void ZPage::reset_type_and_size(ZPageType type) { _type = type; _livemap.resize(object_max_count()); @@ -261,11 +217,11 @@ void ZPage::verify_remset_cleared_previous() const { } void ZPage::clear_remset_current() { - _remembered_set.clear_current(); + _remembered_set.clear_current(); } void ZPage::clear_remset_previous() { - _remembered_set.clear_previous(); + _remembered_set.clear_previous(); } void ZPage::swap_remset_bitmaps() { diff --git a/src/hotspot/share/gc/z/zPage.hpp b/src/hotspot/share/gc/z/zPage.hpp index 3c9b3deda9f..42e14f904bc 100644 --- a/src/hotspot/share/gc/z/zPage.hpp +++ b/src/hotspot/share/gc/z/zPage.hpp @@ -36,16 +36,6 @@ class ZGeneration; -enum class ZPageResetType { - // Normal allocation path - Allocation, - // Relocation failed and started to relocate in-place - InPlaceRelocation, - // Page was not selected for relocation, all objects - // stayed, but the page aged. - FlipAging, -}; - class ZPage : public CHeapObj { friend class VMStructs; friend class ZList; @@ -80,17 +70,13 @@ class ZPage : public CHeapObj { const ZGeneration* generation() const; void reset_seqnum(); - void reset_remembered_set(); ZPage* split_with_pmem(ZPageType type, const ZPhysicalMemory& pmem); - void verify_remset_after_reset(ZPageAge prev_age, ZPageResetType type); - public: ZPage(ZPageType type, const ZVirtualMemory& vmem, const ZPhysicalMemory& pmem); ZPage* clone_limited() const; - ZPage* clone_limited_promote_flipped() const; uint32_t object_max_count() const; size_t object_alignment_shift() const; @@ -126,10 +112,9 @@ class ZPage : public CHeapObj { uint64_t last_used() const; void set_last_used(); - void reset(ZPageAge age, ZPageResetType type); - - void finalize_reset_for_in_place_relocation(); - + void reset(ZPageAge age); + void reset_livemap(); + void reset_top_for_allocation(); void reset_type_and_size(ZPageType type); ZPage* retype(ZPageType type); @@ -170,6 +155,8 @@ class ZPage : public CHeapObj { void clear_remset_range_non_par_current(uintptr_t l_offset, size_t size); void swap_remset_bitmaps(); + void remset_initialize(); + void remset_initialize_or_verify_cleared(); void remset_clear(); ZBitMap::ReverseIterator remset_reverse_iterator_previous(); diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index b1fb1e48373..f5d8ae6e3d1 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -729,7 +729,12 @@ ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags // Reset page. This updates the page's sequence number and must // be done after we potentially blocked in a safepoint (stalled) // where the global sequence number was updated. - page->reset(age, ZPageResetType::Allocation); + page->reset(age); + page->reset_top_for_allocation(); + page->reset_livemap(); + if (age == ZPageAge::old) { + page->remset_initialize_or_verify_cleared(); + } // Update allocation statistics. Exclude gc relocations to avoid // artificial inflation of the allocation rate during relocation. diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index b55a1863bde..90209e4c622 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -843,7 +843,23 @@ class ZRelocateWork : public StackObj { // Promotions happen through a new cloned page ZPage* const to_page = promotion ? from_page->clone_limited() : from_page; - to_page->reset(to_age, ZPageResetType::InPlaceRelocation); + + // Reset page for in-place relocation + to_page->reset(to_age); + to_page->reset_top_for_allocation(); + if (promotion) { + to_page->remset_initialize(); + } + + // Verify that the inactive remset is clear when resetting the page for + // in-place relocation. + if (from_page->age() == ZPageAge::old) { + if (ZGeneration::old()->active_remset_is_current()) { + to_page->verify_remset_cleared_previous(); + } else { + to_page->verify_remset_cleared_current(); + } + } // Clear remset bits for all objects that were relocated // before this page became an in-place relocated page. @@ -1270,8 +1286,14 @@ class ZFlipAgePagesTask : public ZTask { prev_page->log_msg(promotion ? " (flip promoted)" : " (flip survived)"); // Setup to-space page - ZPage* const new_page = promotion ? prev_page->clone_limited_promote_flipped() : prev_page; - new_page->reset(to_age, ZPageResetType::FlipAging); + ZPage* const new_page = promotion ? prev_page->clone_limited() : prev_page; + + // Reset page for flip aging + new_page->reset(to_age); + new_page->reset_livemap(); + if (promotion) { + new_page->remset_initialize(); + } if (promotion) { ZGeneration::young()->flip_promote(prev_page, new_page); diff --git a/src/hotspot/share/gc/z/zRememberedSet.cpp b/src/hotspot/share/gc/z/zRememberedSet.cpp index cb92e38db2e..ed1dcfaf14d 100644 --- a/src/hotspot/share/gc/z/zRememberedSet.cpp +++ b/src/hotspot/share/gc/z/zRememberedSet.cpp @@ -78,8 +78,8 @@ bool ZRememberedSet::is_cleared_previous() const { } void ZRememberedSet::clear_all() { - clear_current(); - clear_previous(); + _bitmap[0].clear_large(); + _bitmap[1].clear_large(); } void ZRememberedSet::clear_current() { diff --git a/src/hotspot/share/interpreter/bytecodeUtils.cpp b/src/hotspot/share/interpreter/bytecodeUtils.cpp index 34fd2b8d566..d86eda0cbe9 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.cpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.cpp @@ -643,7 +643,7 @@ int ExceptionMessageBuilder::do_instruction(int bci) { } } - constantTag tag = cp->tag_at(cp_index); + constantTag tag = cp->constant_tag_at(cp_index); if (tag.is_klass() || tag.is_unresolved_klass() || tag.is_method() || tag.is_interface_method() || tag.is_field() || tag.is_string()) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp index 483c18a3e02..f7873b50058 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -30,7 +30,6 @@ #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrEpochQueue.inline.hpp" #include "jfr/utilities/jfrTypes.hpp" -#include "memory/metaspace.hpp" #include "oops/compressedKlass.inline.hpp" #include "utilities/macros.hpp" @@ -75,13 +74,14 @@ static size_t element_size(bool compressed) { return compressed ? NARROW_ELEMENT_SIZE : ELEMENT_SIZE; } -static bool can_compress_element(traceid id) { - return Metaspace::using_class_space() && id < uncompressed_threshold; +static bool can_compress_element(const Klass* klass) { + return CompressedKlassPointers::is_in_encoding_range(klass) && + JfrTraceId::load_raw(klass) < uncompressed_threshold; } static size_t element_size(const Klass* klass) { assert(klass != nullptr, "invariant"); - return element_size(can_compress_element(JfrTraceId::load_raw(klass))); + return element_size(can_compress_element(klass)); } static bool is_unloaded(traceid id, bool previous_epoch) { @@ -137,7 +137,8 @@ static inline void store_traceid(JfrEpochQueueNarrowKlassElement* element, trace } static void store_compressed_element(traceid id, const Klass* klass, u1* pos) { - assert(can_compress_element(id), "invariant"); + assert(can_compress_element(klass), "invariant"); + assert(id == JfrTraceId::load_raw(klass), "invariant"); JfrEpochQueueNarrowKlassElement* const element = new (pos) JfrEpochQueueNarrowKlassElement(); store_traceid(element, id); element->compressed_klass = encode(klass); @@ -153,7 +154,7 @@ static void store_element(const Klass* klass, u1* pos) { assert(pos != nullptr, "invariant"); assert(klass != nullptr, "invariant"); const traceid id = JfrTraceId::load_raw(klass); - if (can_compress_element(id)) { + if (can_compress_element(klass)) { store_compressed_element(id, klass, pos); return; } diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index 0f2ff7840b8..73bc9d4ad2a 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -75,14 +75,16 @@ void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, MetaspaceObj::Type type, TRAPS) throw() { // Klass has its own operator new - return Metaspace::allocate(loader_data, word_size, type, THREAD); + assert(type != ClassType, "class has its own operator new"); + return Metaspace::allocate(loader_data, word_size, type, /*use_class_space*/ false, THREAD); } void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, MetaspaceObj::Type type) throw() { assert(!Thread::current()->is_Java_thread(), "only allowed by non-Java thread"); - return Metaspace::allocate(loader_data, word_size, type); + assert(type != ClassType, "class has its own operator new"); + return Metaspace::allocate(loader_data, word_size, type, /*use_class_space*/ false); } bool MetaspaceObj::is_valid(const MetaspaceObj* p) { diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index 435a8cfdd58..d1f3f3de7b2 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -311,8 +311,6 @@ void* Arena::grow(size_t x, AllocFailType alloc_failmode) { return result; } - - // Reallocate storage in Arena. void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size, AllocFailType alloc_failmode) { if (new_size == 0) { @@ -324,21 +322,21 @@ void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size, AllocFail return Amalloc(new_size, alloc_failmode); // as with realloc(3), a null old ptr is equivalent to malloc(3) } char *c_old = (char*)old_ptr; // Handy name - // Stupid fast special case - if( new_size <= old_size ) { // Shrink in-place - if( c_old+old_size == _hwm) // Attempt to free the excess bytes - _hwm = c_old+new_size; // Adjust hwm - return c_old; - } - // make sure that new_size is legal + // Make sure that new_size is legal size_t corrected_new_size = ARENA_ALIGN(new_size); - // See if we can resize in-place - if( (c_old+old_size == _hwm) && // Adjusting recent thing - (c_old+corrected_new_size <= _max) ) { // Still fits where it sits - _hwm = c_old+corrected_new_size; // Adjust hwm - return c_old; // Return old pointer + // Reallocating the latest allocation? + if (c_old + old_size == _hwm) { + assert(_chunk->bottom() <= c_old, "invariant"); + + // Reallocate in place if it fits. Also handles shrinking + if (pointer_delta(_max, c_old, 1) >= corrected_new_size) { + _hwm = c_old + corrected_new_size; + return c_old; + } + } else if (new_size <= old_size) { // Shrink in place + return c_old; } // Oops, got to relocate guts diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 9b3b36f8be0..2674278ec99 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -830,7 +830,7 @@ size_t Metaspace::max_allocation_word_size() { // is suitable for calling from non-Java threads. // Callers are responsible for checking null. MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, - MetaspaceObj::Type type) { + MetaspaceObj::Type type, bool use_class_space) { assert(word_size <= Metaspace::max_allocation_word_size(), "allocation size too large (" SIZE_FORMAT ")", word_size); @@ -840,7 +840,7 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, // Deal with concurrent unloading failed allocation starvation MetaspaceCriticalAllocation::block_if_concurrent_purge(); - MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType; + MetadataType mdtype = use_class_space ? ClassType : NonClassType; // Try to allocate metadata. MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype); @@ -856,7 +856,7 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, } MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, - MetaspaceObj::Type type, TRAPS) { + MetaspaceObj::Type type, bool use_class_space, TRAPS) { if (HAS_PENDING_EXCEPTION) { assert(false, "Should not allocate with exception pending"); @@ -864,10 +864,10 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, } assert(!THREAD->owns_locks(), "allocating metaspace while holding mutex"); - MetaWord* result = allocate(loader_data, word_size, type); + MetaWord* result = allocate(loader_data, word_size, type, use_class_space); if (result == nullptr) { - MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType; + MetadataType mdtype = use_class_space ? ClassType : NonClassType; tracer()->report_metaspace_allocation_failure(loader_data, word_size, type, mdtype); // Allocation failed. diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index 6de901b25d1..fc405a389ee 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -110,12 +110,12 @@ class Metaspace : public AllStatic { static size_t max_allocation_word_size(); static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size, - MetaspaceObj::Type type, TRAPS); + MetaspaceObj::Type type, bool use_class_space, TRAPS); // Non-TRAPS version of allocate which can be called by a non-Java thread, that returns // null on failure. static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size, - MetaspaceObj::Type type); + MetaspaceObj::Type type, bool use_class_space); // Returns true if the pointer points into class space, non-class metaspace, or the // metadata portion of the CDS archive. diff --git a/src/hotspot/share/oops/annotations.hpp b/src/hotspot/share/oops/annotations.hpp index 0260de2d8d4..4e9fa56ace9 100644 --- a/src/hotspot/share/oops/annotations.hpp +++ b/src/hotspot/share/oops/annotations.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -89,7 +89,6 @@ class Annotations: public MetaspaceObj { // Turn metadata annotations into a Java heap object (oop) static typeArrayOop make_java_array(AnnotationArray* annotations, TRAPS); - bool is_klass() const { return false; } void metaspace_pointers_do(MetaspaceClosure* it); MetaspaceObj::Type type() const { return AnnotationsType; } diff --git a/src/hotspot/share/oops/array.inline.hpp b/src/hotspot/share/oops/array.inline.hpp index 196792334e5..28f8a35dc0d 100644 --- a/src/hotspot/share/oops/array.inline.hpp +++ b/src/hotspot/share/oops/array.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -34,7 +34,7 @@ template inline void* Array::operator new(size_t size, ClassLoaderData* loader_data, int length, TRAPS) throw() { size_t word_size = Array::size(length); return (void*) Metaspace::allocate(loader_data, word_size, - MetaspaceObj::array_type(sizeof(T)), THREAD); + MetaspaceObj::array_type(sizeof(T)), false, THREAD); } #endif // SHARE_OOPS_ARRAY_INLINE_HPP diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index 275913e3f7f..fd362ae8a06 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -42,6 +42,10 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" +void* ArrayKlass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw() { + return Metaspace::allocate(loader_data, word_size, MetaspaceObj::ClassType, true, THREAD); +} + ArrayKlass::ArrayKlass() { assert(CDSConfig::is_dumping_static_archive() || CDSConfig::is_using_archive(), "only for CDS"); } diff --git a/src/hotspot/share/oops/arrayKlass.hpp b/src/hotspot/share/oops/arrayKlass.hpp index 681d101e0e2..1c1d01fc32a 100644 --- a/src/hotspot/share/oops/arrayKlass.hpp +++ b/src/hotspot/share/oops/arrayKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -49,6 +49,8 @@ class ArrayKlass: public Klass { ArrayKlass(Symbol* name, KlassKind kind); ArrayKlass(); + void* operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw(); + public: // Testing operation DEBUG_ONLY(bool is_array_klass_slow() const { return true; }) diff --git a/src/hotspot/share/oops/compressedKlass.hpp b/src/hotspot/share/oops/compressedKlass.hpp index 1c1bce101a4..26e0a5f6256 100644 --- a/src/hotspot/share/oops/compressedKlass.hpp +++ b/src/hotspot/share/oops/compressedKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -107,6 +107,18 @@ class CompressedKlassPointers : public AllStatic { static inline narrowKlass encode_not_null(Klass* v); static inline narrowKlass encode(Klass* v); + + // Returns whether the pointer is in the memory region used for encoding compressed + // class pointers. This includes CDS. + + // encoding encoding + // base end (base+range) + // |-----------------------------------------------------------------------| + // |----CDS---| |--------------------class space---------------------------| + + static inline bool is_in_encoding_range(const void* p) { + return p >= _base && p < (_base + _range); + } }; #endif // SHARE_OOPS_COMPRESSEDKLASS_HPP diff --git a/src/hotspot/share/oops/constMethod.hpp b/src/hotspot/share/oops/constMethod.hpp index 5f0c49f9319..47fcb0d5572 100644 --- a/src/hotspot/share/oops/constMethod.hpp +++ b/src/hotspot/share/oops/constMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -470,7 +470,6 @@ class ConstMethod : public MetaspaceObj { // Deallocation for RedefineClasses void deallocate_contents(ClassLoaderData* loader_data); - bool is_klass() const { return false; } DEBUG_ONLY(bool on_stack() { return false; }) void metaspace_pointers_do(MetaspaceClosure* it); diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index c741201c833..f95f141d845 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -231,7 +231,6 @@ class ConstantPoolCache: public MetaspaceObj { // RedefineClasses support DEBUG_ONLY(bool on_stack() { return false; }) void deallocate_contents(ClassLoaderData* data); - bool is_klass() const { return false; } void record_gc_epoch(); uint64_t gc_epoch() { return _gc_epoch; } diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 431c7a0e603..fd198f54fc9 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -437,6 +437,11 @@ const char* InstanceKlass::nest_host_error() { } } +void* InstanceKlass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, + bool use_class_space, TRAPS) throw() { + return Metaspace::allocate(loader_data, word_size, ClassType, use_class_space, THREAD); +} + InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) { const int size = InstanceKlass::size(parser.vtable_size(), parser.itable_size(), @@ -449,23 +454,24 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par assert(loader_data != nullptr, "invariant"); InstanceKlass* ik; + const bool use_class_space = !parser.is_interface() && !parser.is_abstract(); // Allocation if (parser.is_instance_ref_klass()) { // java.lang.ref.Reference - ik = new (loader_data, size, THREAD) InstanceRefKlass(parser); + ik = new (loader_data, size, use_class_space, THREAD) InstanceRefKlass(parser); } else if (class_name == vmSymbols::java_lang_Class()) { // mirror - java.lang.Class - ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser); + ik = new (loader_data, size, use_class_space, THREAD) InstanceMirrorKlass(parser); } else if (is_stack_chunk_class(class_name, loader_data)) { // stack chunk - ik = new (loader_data, size, THREAD) InstanceStackChunkKlass(parser); + ik = new (loader_data, size, use_class_space, THREAD) InstanceStackChunkKlass(parser); } else if (is_class_loader(class_name, parser)) { // class loader - java.lang.ClassLoader - ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser); + ik = new (loader_data, size, use_class_space, THREAD) InstanceClassLoaderKlass(parser); } else { // normal - ik = new (loader_data, size, THREAD) InstanceKlass(parser); + ik = new (loader_data, size, use_class_space, THREAD) InstanceKlass(parser); } // Check for pending exception before adding to the loader data and incrementing diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index b639b820d10..eaffa0250d1 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_OOPS_INSTANCEKLASS_HPP #define SHARE_OOPS_INSTANCEKLASS_HPP +#include "memory/allocation.hpp" #include "memory/referenceType.hpp" #include "oops/annotations.hpp" #include "oops/constMethod.hpp" @@ -144,6 +145,8 @@ class InstanceKlass: public Klass { protected: InstanceKlass(const ClassFileParser& parser, KlassKind kind = Kind, ReferenceType reference_type = REF_NONE); + void* operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, bool use_class_space, TRAPS) throw(); + public: InstanceKlass(); diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index f3b625064fb..9e90b4846a6 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -247,10 +247,6 @@ Method* Klass::uncached_lookup_method(const Symbol* name, const Symbol* signatur return nullptr; } -void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw() { - return Metaspace::allocate(loader_data, word_size, MetaspaceObj::ClassType, THREAD); -} - Klass::Klass() : _kind(UnknownKlassKind) { assert(CDSConfig::is_dumping_static_archive() || CDSConfig::is_using_archive(), "only for cds"); } diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index ce74830a311..b782799927b 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -206,8 +206,6 @@ class Klass : public Metadata { Klass(KlassKind kind); Klass(); - void* operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw(); - public: int kind() { return _kind; } diff --git a/src/hotspot/share/oops/recordComponent.hpp b/src/hotspot/share/oops/recordComponent.hpp index f9f4cdb5ee4..2472d3828fd 100644 --- a/src/hotspot/share/oops/recordComponent.hpp +++ b/src/hotspot/share/oops/recordComponent.hpp @@ -83,8 +83,6 @@ class RecordComponent: public MetaspaceObj { static bool is_read_only_by_default() { return true; } DEBUG_ONLY(bool on_stack() { return false; }) // for template - bool is_klass() const { return false; } - #ifndef PRODUCT void print_on(outputStream* st) const; #endif diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 788fbe57fae..58a716abd21 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -754,14 +754,14 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, init_tf(TypeFunc::make(domain, range)); StartNode* s = new StartOSRNode(root(), domain); initial_gvn()->set_type_bottom(s); - init_start(s); + verify_start(s); cg = CallGenerator::for_osr(method(), entry_bci()); } else { // Normal case. init_tf(TypeFunc::make(method())); StartNode* s = new StartNode(root(), tf()->domain()); initial_gvn()->set_type_bottom(s); - init_start(s); + verify_start(s); if (method()->intrinsic_id() == vmIntrinsics::_Reference_get) { // With java.lang.ref.reference.get() we must go through the // intrinsic - even when get() is the root @@ -1105,13 +1105,12 @@ void Compile::Init(bool aliasing) { probe_alias_cache(nullptr)->_index = AliasIdxTop; } -//---------------------------init_start---------------------------------------- -// Install the StartNode on this compile object. -void Compile::init_start(StartNode* s) { - if (failing()) - return; // already failing - assert(s == start(), ""); +#ifdef ASSERT +// Verify that the current StartNode is valid. +void Compile::verify_start(StartNode* s) const { + assert(failing() || s == start(), "should be StartNode"); } +#endif /** * Return the 'StartNode'. We must not have a pending failure, since the ideal graph @@ -5198,7 +5197,20 @@ void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { ss.print(" %d", iter); } if (n != nullptr) { - ss.print(": %d %s ", n->_idx, NodeClassNames[n->Opcode()]); + ss.print(": %d %s", n->_idx, NodeClassNames[n->Opcode()]); + if (n->is_Call()) { + CallNode* call = n->as_Call(); + if (call->_name != nullptr) { + // E.g. uncommon traps etc. + ss.print(" - %s", call->_name); + } else if (call->is_CallJava()) { + CallJavaNode* call_java = call->as_CallJava(); + if (call_java->method() != nullptr) { + ss.print(" -"); + call_java->method()->print_short_name(&ss); + } + } + } } const char* name = ss.as_string(); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 15c91f6ad12..e1574da568b 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -864,7 +864,7 @@ class Compile : public Phase { RootNode* root() const { return _root; } void set_root(RootNode* r) { _root = r; } StartNode* start() const; // (Derived from root.) - void init_start(StartNode* s); + void verify_start(StartNode* s) const NOT_DEBUG_RETURN; Node* immutable_memory(); Node* recent_alloc_ctl() const { return _recent_alloc_ctl; } diff --git a/src/hotspot/share/opto/generateOptoStub.cpp b/src/hotspot/share/opto/generateOptoStub.cpp index e22f484c179..2f940439045 100644 --- a/src/hotspot/share/opto/generateOptoStub.cpp +++ b/src/hotspot/share/opto/generateOptoStub.cpp @@ -261,7 +261,7 @@ void GraphKit::gen_stub(address C_function, frameptr(), returnadr()); root()->add_req(_gvn.transform(to_exc)); // bind to root to keep live - C->init_start(start); + C->verify_start(start); //----------------------------- // If this is a normal subroutine return, issue the return and be done. diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 6e537054643..59662ad53fe 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1683,8 +1683,8 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n // use by range check elimination. Node *pre_opaq = new Opaque1Node(C, pre_limit, limit); - register_new_node(pre_limit, pre_head->in(0)); - register_new_node(pre_opaq , pre_head->in(0)); + register_new_node(pre_limit, pre_head->in(LoopNode::EntryControl)); + register_new_node(pre_opaq , pre_head->in(LoopNode::EntryControl)); // Since no other users of pre-loop compare, I can hack limit directly assert(cmp_end->outcnt() == 1, "no other users"); @@ -2790,6 +2790,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // Find the main loop limit; we will trim it's iterations // to not ever trip end tests Node *main_limit = cl->limit(); + Node* main_limit_ctrl = get_ctrl(main_limit); // Check graph shape. Cannot optimize a loop if zero-trip // Opaque1 node is optimized away and then another round @@ -2822,9 +2823,15 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { } Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1; Node *pre_limit = pre_opaq->in(1); + Node* pre_limit_ctrl = get_ctrl(pre_limit); // Where do we put new limit calculations - Node *pre_ctrl = pre_end->loopnode()->in(LoopNode::EntryControl); + Node* pre_ctrl = pre_end->loopnode()->in(LoopNode::EntryControl); + // Range check elimination optimizes out conditions whose parameters are loop invariant in the main loop. They usually + // have control above the pre loop, but there's no guarantee that they do. There's no guarantee either that the pre + // loop limit has control that's out of loop (a previous round of range check elimination could have set a limit that's + // not loop invariant). + Node* new_limit_ctrl = dominated_node(pre_ctrl, pre_limit_ctrl); // Ensure the original loop limit is available from the // pre-loop Opaque1 node. @@ -2884,14 +2891,14 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { Node *limit = cmp->in(2); int scale_con= 1; // Assume trip counter not scaled - Node *limit_c = get_ctrl(limit); - if (loop->is_member(get_loop(limit_c))) { + Node* limit_ctrl = get_ctrl(limit); + if (loop->is_member(get_loop(limit_ctrl))) { // Compare might have operands swapped; commute them b_test = b_test.commute(); rc_exp = cmp->in(2); limit = cmp->in(1); - limit_c = get_ctrl(limit); - if (loop->is_member(get_loop(limit_c))) { + limit_ctrl = get_ctrl(limit); + if (loop->is_member(get_loop(limit_ctrl))) { continue; // Both inputs are loop varying; cannot RCE } } @@ -2900,11 +2907,11 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // 'limit' maybe pinned below the zero trip test (probably from a // previous round of rce), in which case, it can't be used in the // zero trip test expression which must occur before the zero test's if. - if (is_dominator(ctrl, limit_c)) { + if (is_dominator(ctrl, limit_ctrl)) { continue; // Don't rce this check but continue looking for other candidates. } - assert(is_dominator(compute_early_ctrl(limit, limit_c), pre_end), "node pinned on loop exit test?"); + assert(is_dominator(compute_early_ctrl(limit, limit_ctrl), pre_end), "node pinned on loop exit test?"); // Check for scaled induction variable plus an offset Node *offset = nullptr; @@ -2913,19 +2920,26 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { continue; } - Node *offset_c = get_ctrl(offset); - if (loop->is_member(get_loop(offset_c))) { + Node* offset_ctrl = get_ctrl(offset); + if (loop->is_member(get_loop(offset_ctrl))) { continue; // Offset is not really loop invariant } // Here we know 'offset' is loop invariant. // As above for the 'limit', the 'offset' maybe pinned below the // zero trip test. - if (is_dominator(ctrl, offset_c)) { + if (is_dominator(ctrl, offset_ctrl)) { continue; // Don't rce this check but continue looking for other candidates. } - assert(is_dominator(compute_early_ctrl(offset, offset_c), pre_end), "node pinned on loop exit test?"); + // offset and limit can have control set below the pre loop when they are not loop invariant in the pre loop. + // Update their control (and the control of inputs as needed) to be above pre_end + offset_ctrl = ensure_node_and_inputs_are_above_pre_end(pre_end, offset); + limit_ctrl = ensure_node_and_inputs_are_above_pre_end(pre_end, limit); + + // offset and limit could have control below new_limit_ctrl if they are not loop invariant in the pre loop. + new_limit_ctrl = dominated_node(new_limit_ctrl, offset_ctrl, limit_ctrl); + #ifdef ASSERT if (TraceRangeLimitCheck) { tty->print_cr("RC bool node%s", flip ? " flipped:" : ":"); @@ -2945,16 +2959,16 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { jlong lscale_con = scale_con; Node* int_offset = offset; offset = new ConvI2LNode(offset); - register_new_node(offset, pre_ctrl); + register_new_node(offset, new_limit_ctrl); Node* int_limit = limit; limit = new ConvI2LNode(limit); - register_new_node(limit, pre_ctrl); + register_new_node(limit, new_limit_ctrl); // Adjust pre and main loop limits to guard the correct iteration set if (cmp->Opcode() == Op_CmpU) { // Unsigned compare is really 2 tests if (b_test._test == BoolTest::lt) { // Range checks always use lt // The underflow and overflow limits: 0 <= scale*I+offset < limit - add_constraint(stride_con, lscale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit); + add_constraint(stride_con, lscale_con, offset, zero, limit, new_limit_ctrl, &pre_limit, &main_limit); Node* init = cl->init_trip(); Node* opaque_init = new OpaqueLoopInitNode(C, init); register_new_node(opaque_init, loop_entry); @@ -3013,22 +3027,22 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // Convert (I*scale+offset) >= Limit to (I*(-scale)+(-offset)) <= -Limit lscale_con = -lscale_con; offset = new SubLNode(zero, offset); - register_new_node(offset, pre_ctrl); + register_new_node(offset, new_limit_ctrl); limit = new SubLNode(zero, limit); - register_new_node(limit, pre_ctrl); + register_new_node(limit, new_limit_ctrl); // Fall into LE case case BoolTest::le: if (b_test._test != BoolTest::gt) { // Convert X <= Y to X < Y+1 limit = new AddLNode(limit, one); - register_new_node(limit, pre_ctrl); + register_new_node(limit, new_limit_ctrl); } // Fall into LT case case BoolTest::lt: // The underflow and overflow limits: MIN_INT <= scale*I+offset < limit // Note: (MIN_INT+1 == -MAX_INT) is used instead of MIN_INT here // to avoid problem with scale == -1: MIN_INT/(-1) == MIN_INT. - add_constraint(stride_con, lscale_con, offset, mini, limit, pre_ctrl, &pre_limit, &main_limit); + add_constraint(stride_con, lscale_con, offset, mini, limit, new_limit_ctrl, &pre_limit, &main_limit); break; default: if (PrintOpto) { @@ -3072,8 +3086,14 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // Computed pre-loop limit can be outside of loop iterations range. pre_limit = (stride_con > 0) ? (Node*)new MinINode(pre_limit, orig_limit) : (Node*)new MaxINode(pre_limit, orig_limit); - register_new_node(pre_limit, pre_ctrl); + register_new_node(pre_limit, new_limit_ctrl); } + // new pre_limit can push Bool/Cmp/Opaque nodes down (when one of the eliminated condition has parameters that are not + // loop invariant in the pre loop. + set_ctrl(pre_opaq, new_limit_ctrl); + set_ctrl(pre_end->cmp_node(), new_limit_ctrl); + set_ctrl(pre_end->in(1), new_limit_ctrl); + _igvn.replace_input_of(pre_opaq, 1, pre_limit); // Note:: we are making the main loop limit no longer precise; @@ -3093,7 +3113,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { register_new_node(main_cmp, main_cle->in(0)); _igvn.replace_input_of(main_bol, 1, main_cmp); } - assert(main_limit == cl->limit() || get_ctrl(main_limit) == pre_ctrl, "wrong control for added limit"); + assert(main_limit == cl->limit() || get_ctrl(main_limit) == new_limit_ctrl, "wrong control for added limit"); const TypeInt* orig_limit_t = _igvn.type(orig_limit)->is_int(); bool upward = cl->stride_con() > 0; // The new loop limit is <= (for an upward loop) >= (for a downward loop) than the orig limit. @@ -3101,7 +3121,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // may be too pessimistic. A CastII here guarantees it's not lost. main_limit = new CastIINode(pre_ctrl, main_limit, TypeInt::make(upward ? min_jint : orig_limit_t->_lo, upward ? orig_limit_t->_hi : max_jint, Type::WidenMax)); - register_new_node(main_limit, pre_ctrl); + register_new_node(main_limit, new_limit_ctrl); // Hack the now-private loop bounds _igvn.replace_input_of(main_cmp, 2, main_limit); if (abs_stride_is_one) { @@ -3112,6 +3132,37 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // The OpaqueNode is unshared by design assert(opqzm->outcnt() == 1, "cannot hack shared node"); _igvn.replace_input_of(opqzm, 1, main_limit); + // new main_limit can push Bool/Cmp nodes down (when one of the eliminated condition has parameters that are not loop + // invariant in the pre loop. + set_ctrl(opqzm, new_limit_ctrl); + set_ctrl(iffm->in(1)->in(1), new_limit_ctrl); + set_ctrl(iffm->in(1), new_limit_ctrl); +} + +// Adjust control for node and its inputs (and inputs of its inputs) to be above the pre end +Node* PhaseIdealLoop::ensure_node_and_inputs_are_above_pre_end(CountedLoopEndNode* pre_end, Node* node) { + Node* control = get_ctrl(node); + assert(is_dominator(compute_early_ctrl(node, control), pre_end), "node pinned on loop exit test?"); + + if (is_dominator(control, pre_end)) { + return control; + } + control = pre_end->in(0); + ResourceMark rm; + Unique_Node_List wq; + wq.push(node); + for (uint i = 0; i < wq.size(); i++) { + Node* n = wq.at(i); + assert(is_dominator(compute_early_ctrl(n, get_ctrl(n)), pre_end), "node pinned on loop exit test?"); + set_ctrl(n, control); + for (uint j = 0; j < n->req(); j++) { + Node* in = n->in(j); + if (in != nullptr && has_ctrl(in) && !is_dominator(get_ctrl(in), pre_end)) { + wq.push(in); + } + } + } + return control; } bool IdealLoopTree::compute_has_range_checks() const { diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index b4c134570e6..3128e23d79c 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -4511,23 +4511,6 @@ bool PhaseIdealLoop::process_expensive_nodes() { return progress; } -#ifdef ASSERT -// Goes over all children of the root of the loop tree. Check if any of them have a path -// down to Root, that does not go via a NeverBranch exit. -bool PhaseIdealLoop::only_has_infinite_loops() { - ResourceMark rm; - Unique_Node_List worklist; - // start traversal at all loop heads of first-level loops - for (IdealLoopTree* l = _ltree_root->_child; l != nullptr; l = l->_next) { - Node* head = l->_head; - assert(head->is_Region(), ""); - worklist.push(head); - } - return RegionNode::are_all_nodes_in_infinite_subgraph(worklist); -} -#endif - - //============================================================================= //----------------------------build_and_optimize------------------------------- // Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to @@ -4586,13 +4569,9 @@ void PhaseIdealLoop::build_and_optimize() { return; } - // Verify that the has_loops() flag set at parse time is consistent - // with the just built loop tree. With infinite loops, it could be - // that one pass of loop opts only finds infinite loops, clears the - // has_loops() flag but adds NeverBranch nodes so the next loop opts - // verification pass finds a non empty loop tree. When the back edge + // Verify that the has_loops() flag set at parse time is consistent with the just built loop tree. When the back edge // is an exception edge, parsing doesn't set has_loops(). - assert(_ltree_root->_child == nullptr || C->has_loops() || only_has_infinite_loops() || C->has_exception_backedge(), "parsing found no loops but there are some"); + assert(_ltree_root->_child == nullptr || C->has_loops() || C->has_exception_backedge(), "parsing found no loops but there are some"); // No loops after all if( !_ltree_root->_child && !_verify_only ) C->set_has_loops(false); @@ -5425,7 +5404,7 @@ void PhaseIdealLoop::build_loop_tree() { if ( bltstack.length() == stack_size ) { // There were no additional children, post visit node now (void)bltstack.pop(); // Remove node from stack - pre_order = build_loop_tree_impl( n, pre_order ); + pre_order = build_loop_tree_impl(n, pre_order); // Check for bailout if (C->failing()) { return; @@ -5443,7 +5422,7 @@ void PhaseIdealLoop::build_loop_tree() { } //------------------------------build_loop_tree_impl--------------------------- -int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { +int PhaseIdealLoop::build_loop_tree_impl(Node* n, int pre_order) { // ---- Post-pass Work ---- // Pre-walked but not post-walked nodes need a pre_order number. @@ -5454,24 +5433,24 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // for it. Then find the tightest enclosing loop for the self Node. for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* m = n->fast_out(i); // Child - if( n == m ) continue; // Ignore control self-cycles - if( !m->is_CFG() ) continue;// Ignore non-CFG edges + if (n == m) continue; // Ignore control self-cycles + if (!m->is_CFG()) continue;// Ignore non-CFG edges IdealLoopTree *l; // Child's loop - if( !is_postvisited(m) ) { // Child visited but not post-visited? + if (!is_postvisited(m)) { // Child visited but not post-visited? // Found a backedge - assert( get_preorder(m) < pre_order, "should be backedge" ); + assert(get_preorder(m) < pre_order, "should be backedge"); // Check for the RootNode, which is already a LoopNode and is allowed // to have multiple "backedges". - if( m == C->root()) { // Found the root? + if (m == C->root()) { // Found the root? l = _ltree_root; // Root is the outermost LoopNode } else { // Else found a nested loop // Insert a LoopNode to mark this loop. l = new IdealLoopTree(this, m, n); } // End of Else found a nested loop - if( !has_loop(m) ) // If 'm' does not already have a loop set + if (!has_loop(m)) { // If 'm' does not already have a loop set set_loop(m, l); // Set loop header to loop now - + } } else { // Else not a nested loop if (!_loop_or_ctrl[m->_idx]) continue; // Dead code has no loop IdealLoopTree* m_loop = get_loop(m); @@ -5480,23 +5459,17 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // is a member of some outer enclosing loop. Since there are no // shared headers (I've split them already) I only need to go up // at most 1 level. - while( l && l->_head == m ) // Successor heads loop? + while (l && l->_head == m) { // Successor heads loop? l = l->_parent; // Move up 1 for me + } // If this loop is not properly parented, then this loop // has no exit path out, i.e. its an infinite loop. - if( !l ) { + if (!l) { // Make loop "reachable" from root so the CFG is reachable. Basically // insert a bogus loop exit that is never taken. 'm', the loop head, // points to 'n', one (of possibly many) fall-in paths. There may be // many backedges as well. - // Here I set the loop to be the root loop. I could have, after - // inserting a bogus loop exit, restarted the recursion and found my - // new loop exit. This would make the infinite loop a first-class - // loop and it would then get properly optimized. What's the use of - // optimizing an infinite loop? - l = _ltree_root; // Oops, found infinite loop - if (!_verify_only) { // Insert the NeverBranch between 'm' and it's control user. NeverBranchNode *iff = new NeverBranchNode( m ); @@ -5520,7 +5493,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // Now create the never-taken loop exit Node *if_f = new CProjNode( iff, 1 ); _igvn.register_new_node_with_optimizer(if_f); - set_loop(if_f, l); + set_loop(if_f, _ltree_root); // Find frame ptr for Halt. Relies on the optimizer // V-N'ing. Easier and quicker than searching through // the program structure. @@ -5529,10 +5502,27 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // Halt & Catch Fire Node* halt = new HaltNode(if_f, frame, "never-taken loop exit reached"); _igvn.register_new_node_with_optimizer(halt); - set_loop(halt, l); + set_loop(halt, _ltree_root); _igvn.add_input_to(C->root(), halt); } set_loop(C->root(), _ltree_root); + // move to outer most loop with same header + l = m_loop; + while (true) { + IdealLoopTree* next = l->_parent; + if (next == nullptr || next->_head != m) { + break; + } + l = next; + } + // properly insert infinite loop in loop tree + sort(_ltree_root, l); + // fix child link from parent + IdealLoopTree* p = l->_parent; + l->_next = p->_child; + p->_child = l; + // code below needs enclosing loop + l = l->_parent; } } if (is_postvisited(l->_head)) { @@ -5586,7 +5576,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { assert( get_loop(n) == innermost, "" ); IdealLoopTree *p = innermost->_parent; IdealLoopTree *l = innermost; - while( p && l->_head == n ) { + while (p && l->_head == n) { l->_next = p->_child; // Put self on parents 'next child' p->_child = l; // Make self as first child of parent l = p; // Now walk up the parent chain @@ -5600,7 +5590,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // Record tightest enclosing loop for self. Mark as post-visited. set_loop(n, innermost); // Also record has_call flag early on - if( innermost ) { + if (innermost) { if( n->is_Call() && !n->is_CallLeaf() && !n->is_macro() ) { // Do not count uncommon calls if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 369f446adbb..2d169a6459b 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -966,10 +966,6 @@ class PhaseIdealLoop : public PhaseTransform { const Node_List& old_new); void insert_loop_limit_check_predicate(ParsePredicateSuccessProj* loop_limit_check_parse_proj, Node* cmp_limit, Node* bol); -#ifdef ASSERT - bool only_has_infinite_loops(); -#endif - void log_loop_tree(); public: @@ -1076,7 +1072,7 @@ class PhaseIdealLoop : public PhaseTransform { // Place 'n' in some loop nest, where 'n' is a CFG node void build_loop_tree(); - int build_loop_tree_impl( Node *n, int pre_order ); + int build_loop_tree_impl(Node* n, int pre_order); // Insert loop into the existing loop tree. 'innermost' is a leaf of the // loop tree, not the root. IdealLoopTree *sort( IdealLoopTree *loop, IdealLoopTree *innermost ); @@ -1184,6 +1180,16 @@ class PhaseIdealLoop : public PhaseTransform { } Node *dom_lca_internal( Node *n1, Node *n2 ) const; + Node* dominated_node(Node* c1, Node* c2) { + assert(is_dominator(c1, c2) || is_dominator(c2, c1), "nodes must be related"); + return is_dominator(c1, c2) ? c2 : c1; + } + + // Return control node that's dominated by the 2 others + Node* dominated_node(Node* c1, Node* c2, Node* c3) { + return dominated_node(c1, dominated_node(c2, c3)); + } + // Build and verify the loop tree without modifying the graph. This // is useful to verify that all inputs properly dominate their uses. static void verify(PhaseIterGVN& igvn) { @@ -1784,6 +1790,8 @@ class PhaseIdealLoop : public PhaseTransform { bool can_move_to_inner_loop(Node* n, LoopNode* n_loop, Node* x); void pin_array_access_nodes_dependent_on(Node* ctrl); + + Node* ensure_node_and_inputs_are_above_pre_end(CountedLoopEndNode* pre_end, Node* node); }; diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 1f22c608323..ad98fda025f 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -594,6 +594,69 @@ const Type* MulHiValue(const Type *t1, const Type *t2, const Type *bot) { return TypeLong::LONG; } +template +static const IntegerType* and_value(const IntegerType* r0, const IntegerType* r1) { + typedef typename IntegerType::NativeType NativeType; + static_assert(std::is_signed::value, "Native type of IntegerType must be signed!"); + + int widen = MAX2(r0->_widen, r1->_widen); + + // If both types are constants, we can calculate a constant result. + if (r0->is_con() && r1->is_con()) { + return IntegerType::make(r0->get_con() & r1->get_con()); + } + + // If both ranges are positive, the result will range from 0 up to the hi value of the smaller range. The minimum + // of the two constrains the upper bound because any higher value in the other range will see all zeroes, so it will be masked out. + if (r0->_lo >= 0 && r1->_lo >= 0) { + return IntegerType::make(0, MIN2(r0->_hi, r1->_hi), widen); + } + + // If only one range is positive, the result will range from 0 up to that range's maximum value. + // For the operation 'x & C' where C is a positive constant, the result will be in the range [0..C]. With that observation, + // we can say that for any integer c such that 0 <= c <= C will also be in the range [0..C]. Therefore, 'x & [c..C]' + // where c >= 0 will be in the range [0..C]. + if (r0->_lo >= 0) { + return IntegerType::make(0, r0->_hi, widen); + } + + if (r1->_lo >= 0) { + return IntegerType::make(0, r1->_hi, widen); + } + + // At this point, all positive ranges will have already been handled, so the only remaining cases will be negative ranges + // and constants. + + assert(r0->_lo < 0 && r1->_lo < 0, "positive ranges should already be handled!"); + + // As two's complement means that both numbers will start with leading 1s, the lower bound of both ranges will contain + // the common leading 1s of both minimum values. In order to count them with count_leading_zeros, the bits are inverted. + NativeType sel_val = ~MIN2(r0->_lo, r1->_lo); + + NativeType min; + if (sel_val == 0) { + // Since count_leading_zeros is undefined at 0, we short-circuit the condition where both ranges have a minimum of -1. + min = -1; + } else { + // To get the number of bits to shift, we count the leading 0-bits and then subtract one, as the sign bit is already set. + int shift_bits = count_leading_zeros(sel_val) - 1; + min = std::numeric_limits::min() >> shift_bits; + } + + NativeType max; + if (r0->_hi < 0 && r1->_hi < 0) { + // If both ranges are negative, then the same optimization as both positive ranges will apply, and the smaller hi + // value will mask off any bits set by higher values. + max = MIN2(r0->_hi, r1->_hi); + } else { + // In the case of ranges that cross zero, negative values can cause the higher order bits to be set, so the maximum + // positive value can be as high as the larger hi value. + max = MAX2(r0->_hi, r1->_hi); + } + + return IntegerType::make(min, max, widen); +} + //============================================================================= //------------------------------mul_ring--------------------------------------- // Supplied function returns the product of the inputs IN THE CURRENT RING. @@ -601,29 +664,10 @@ const Type* MulHiValue(const Type *t1, const Type *t2, const Type *bot) { // This also type-checks the inputs for sanity. Guaranteed never to // be passed a TOP or BOTTOM type, these are filtered out by pre-check. const Type *AndINode::mul_ring( const Type *t0, const Type *t1 ) const { - const TypeInt *r0 = t0->is_int(); // Handy access - const TypeInt *r1 = t1->is_int(); - int widen = MAX2(r0->_widen,r1->_widen); - - // If either input is a constant, might be able to trim cases - if( !r0->is_con() && !r1->is_con() ) - return TypeInt::INT; // No constants to be had - - // Both constants? Return bits - if( r0->is_con() && r1->is_con() ) - return TypeInt::make( r0->get_con() & r1->get_con() ); - - if( r0->is_con() && r0->get_con() > 0 ) - return TypeInt::make(0, r0->get_con(), widen); + const TypeInt* r0 = t0->is_int(); + const TypeInt* r1 = t1->is_int(); - if( r1->is_con() && r1->get_con() > 0 ) - return TypeInt::make(0, r1->get_con(), widen); - - if( r0 == TypeInt::BOOL || r1 == TypeInt::BOOL ) { - return TypeInt::BOOL; - } - - return TypeInt::INT; // No constants to be had + return and_value(r0, r1); } const Type* AndINode::Value(PhaseGVN* phase) const { @@ -751,25 +795,10 @@ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) { // This also type-checks the inputs for sanity. Guaranteed never to // be passed a TOP or BOTTOM type, these are filtered out by pre-check. const Type *AndLNode::mul_ring( const Type *t0, const Type *t1 ) const { - const TypeLong *r0 = t0->is_long(); // Handy access - const TypeLong *r1 = t1->is_long(); - int widen = MAX2(r0->_widen,r1->_widen); - - // If either input is a constant, might be able to trim cases - if( !r0->is_con() && !r1->is_con() ) - return TypeLong::LONG; // No constants to be had - - // Both constants? Return bits - if( r0->is_con() && r1->is_con() ) - return TypeLong::make( r0->get_con() & r1->get_con() ); - - if( r0->is_con() && r0->get_con() > 0 ) - return TypeLong::make(CONST64(0), r0->get_con(), widen); - - if( r1->is_con() && r1->get_con() > 0 ) - return TypeLong::make(CONST64(0), r1->get_con(), widen); + const TypeLong* r0 = t0->is_long(); + const TypeLong* r1 = t1->is_long(); - return TypeLong::LONG; // No constants to be had + return and_value(r0, r1); } const Type* AndLNode::Value(PhaseGVN* phase) const { diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 50ccc147322..d4a6a9ce5b7 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1651,7 +1651,7 @@ void Parse::merge_new_path(int target_bci) { // The ex_oop must be pushed on the stack, unlike throw_to_exit. void Parse::merge_exception(int target_bci) { #ifdef ASSERT - if (target_bci < bci()) { + if (target_bci <= bci()) { C->set_exception_backedge(); } #endif diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 8a08a12a0b0..87f4a751e80 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2497,6 +2497,13 @@ WB_ENTRY(jint, WB_ValidateCgroup(JNIEnv* env, return ret; WB_END +// Available cpus of the host machine, Linux only. +// Used in container testing. +WB_ENTRY(jint, WB_HostCPUs(JNIEnv* env, jobject o)) + LINUX_ONLY(return os::Linux::active_processor_count();) + return -1; // Not used/implemented on other platforms +WB_END + WB_ENTRY(void, WB_PrintOsInfo(JNIEnv* env, jobject o)) os::print_os_info(tty); WB_END @@ -2938,6 +2945,7 @@ static JNINativeMethod methods[] = { (void*)&WB_ValidateCgroup }, {CC"hostPhysicalMemory", CC"()J", (void*)&WB_HostPhysicalMemory }, {CC"hostPhysicalSwap", CC"()J", (void*)&WB_HostPhysicalSwap }, + {CC"hostCPUs", CC"()I", (void*)&WB_HostCPUs }, {CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo }, {CC"disableElfSectionCache", CC"()V", (void*)&WB_DisableElfSectionCache }, {CC"resolvedMethodItemsCount", CC"()J", (void*)&WB_ResolvedMethodItemsCount }, diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 0a763d76bad..5d578fa741e 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -277,12 +277,31 @@ class Config { } }; +#ifdef _WINDOWS +static void map_stack_pages(JavaThread* thread, size_t size, address sp) { + address new_sp = sp - size; + address watermark = thread->stack_overflow_state()->shadow_zone_growth_watermark(); + + if (new_sp < watermark) { + size_t page_size = os::vm_page_size(); + address last_touched_page = watermark - StackOverflow::stack_shadow_zone_size(); + size_t pages_to_touch = align_up(watermark - new_sp, page_size) / page_size; + while (pages_to_touch-- > 0) { + last_touched_page -= page_size; + *last_touched_page = 0; + } + thread->stack_overflow_state()->set_shadow_zone_growth_watermark(new_sp); + } +} +#endif + static bool stack_overflow_check(JavaThread* thread, size_t size, address sp) { const size_t page_size = os::vm_page_size(); if (size > page_size) { if (sp - size < thread->stack_overflow_state()->shadow_zone_safe_limit()) { return false; } + WINDOWS_ONLY(map_stack_pages(thread, size, sp)); } return true; } diff --git a/src/hotspot/share/runtime/flags/allFlags.hpp b/src/hotspot/share/runtime/flags/allFlags.hpp index af5645b2b8f..edeb1cd4024 100644 --- a/src/hotspot/share/runtime/flags/allFlags.hpp +++ b/src/hotspot/share/runtime/flags/allFlags.hpp @@ -57,15 +57,15 @@ range, \ constraint) \ \ - CDS_FLAGS( \ + JVMCI_ONLY(JVMCI_FLAGS( \ develop, \ develop_pd, \ product, \ product_pd, \ range, \ - constraint) \ + constraint)) \ \ - JVMCI_ONLY(JVMCI_FLAGS( \ + COMPILER1_PRESENT(C1_FLAGS( \ develop, \ develop_pd, \ product, \ @@ -73,7 +73,7 @@ range, \ constraint)) \ \ - COMPILER1_PRESENT(C1_FLAGS( \ + COMPILER2_PRESENT(C2_FLAGS( \ develop, \ develop_pd, \ product, \ @@ -81,15 +81,15 @@ range, \ constraint)) \ \ - COMPILER2_PRESENT(C2_FLAGS( \ + COMPILER_FLAGS( \ develop, \ develop_pd, \ product, \ product_pd, \ range, \ - constraint)) \ + constraint) \ \ - COMPILER_FLAGS( \ + CDS_FLAGS( \ develop, \ develop_pd, \ product, \ diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index f98d031a2cd..d9b38133f99 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -92,61 +92,61 @@ // Shared runtime stub routines reside in their own unique blob with a // single entry point -RuntimeStub* SharedRuntime::_wrong_method_blob; -RuntimeStub* SharedRuntime::_wrong_method_abstract_blob; -RuntimeStub* SharedRuntime::_ic_miss_blob; -RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob; -RuntimeStub* SharedRuntime::_resolve_virtual_call_blob; -RuntimeStub* SharedRuntime::_resolve_static_call_blob; - -DeoptimizationBlob* SharedRuntime::_deopt_blob; -SafepointBlob* SharedRuntime::_polling_page_vectors_safepoint_handler_blob; -SafepointBlob* SharedRuntime::_polling_page_safepoint_handler_blob; -SafepointBlob* SharedRuntime::_polling_page_return_handler_blob; - -RuntimeStub* SharedRuntime::_throw_AbstractMethodError_blob; -RuntimeStub* SharedRuntime::_throw_IncompatibleClassChangeError_blob; -RuntimeStub* SharedRuntime::_throw_NullPointerException_at_call_blob; -RuntimeStub* SharedRuntime::_throw_StackOverflowError_blob; -RuntimeStub* SharedRuntime::_throw_delayed_StackOverflowError_blob; -#if INCLUDE_JFR -RuntimeStub* SharedRuntime::_jfr_write_checkpoint_blob = nullptr; -RuntimeStub* SharedRuntime::_jfr_return_lease_blob = nullptr; -#endif +#define SHARED_STUB_FIELD_DEFINE(name, type) \ + type SharedRuntime::BLOB_FIELD_NAME(name); + SHARED_STUBS_DO(SHARED_STUB_FIELD_DEFINE) +#undef SHARED_STUB_FIELD_DEFINE nmethod* SharedRuntime::_cont_doYield_stub; +#define SHARED_STUB_NAME_DECLARE(name, type) "Shared Runtime " # name "_blob", +const char *SharedRuntime::_stub_names[] = { + SHARED_STUBS_DO(SHARED_STUB_NAME_DECLARE) +}; + //----------------------------generate_stubs----------------------------------- void SharedRuntime::generate_initial_stubs() { // Build this early so it's available for the interpreter. _throw_StackOverflowError_blob = - generate_throw_exception("StackOverflowError throw_exception", + generate_throw_exception(SharedStubId::throw_StackOverflowError_id, CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); } void SharedRuntime::generate_stubs() { - _wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method), "wrong_method_stub"); - _wrong_method_abstract_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_abstract), "wrong_method_abstract_stub"); - _ic_miss_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss), "ic_miss_stub"); - _resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C), "resolve_opt_virtual_call"); - _resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call"); - _resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call"); + _wrong_method_blob = + generate_resolve_blob(SharedStubId::wrong_method_id, + CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method)); + _wrong_method_abstract_blob = + generate_resolve_blob(SharedStubId::wrong_method_abstract_id, + CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_abstract)); + _ic_miss_blob = + generate_resolve_blob(SharedStubId::ic_miss_id, + CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss)); + _resolve_opt_virtual_call_blob = + generate_resolve_blob(SharedStubId::resolve_opt_virtual_call_id, + CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C)); + _resolve_virtual_call_blob = + generate_resolve_blob(SharedStubId::resolve_virtual_call_id, + CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C)); + _resolve_static_call_blob = + generate_resolve_blob(SharedStubId::resolve_static_call_id, + CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C)); _throw_delayed_StackOverflowError_blob = - generate_throw_exception("delayed StackOverflowError throw_exception", + generate_throw_exception(SharedStubId::throw_delayed_StackOverflowError_id, CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); _throw_AbstractMethodError_blob = - generate_throw_exception("AbstractMethodError throw_exception", + generate_throw_exception(SharedStubId::throw_AbstractMethodError_id, CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); _throw_IncompatibleClassChangeError_blob = - generate_throw_exception("IncompatibleClassChangeError throw_exception", + generate_throw_exception(SharedStubId::throw_IncompatibleClassChangeError_id, CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); _throw_NullPointerException_at_call_blob = - generate_throw_exception("NullPointerException at call throw_exception", + generate_throw_exception(SharedStubId::throw_NullPointerException_at_call_id, CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); AdapterHandlerLibrary::initialize(); @@ -155,11 +155,17 @@ void SharedRuntime::generate_stubs() { // Vectors are generated only by C2 and JVMCI. bool support_wide = is_wide_vector(MaxVectorSize); if (support_wide) { - _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP); + _polling_page_vectors_safepoint_handler_blob = + generate_handler_blob(SharedStubId::polling_page_vectors_safepoint_handler_id, + CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception)); } #endif // COMPILER2_OR_JVMCI - _polling_page_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_LOOP); - _polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_RETURN); + _polling_page_safepoint_handler_blob = + generate_handler_blob(SharedStubId::polling_page_safepoint_handler_id, + CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception)); + _polling_page_return_handler_blob = + generate_handler_blob(SharedStubId::polling_page_return_handler_id, + CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception)); generate_deopt_blob(); } diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 00a72f5db1e..f530c0ad2a8 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -30,6 +30,7 @@ #include "interpreter/linkResolver.hpp" #include "memory/allStatic.hpp" #include "memory/resourceArea.hpp" +#include "runtime/stubDeclarations.hpp" #include "utilities/macros.hpp" class AdapterHandlerEntry; @@ -42,37 +43,57 @@ class vframeStream; // Java exceptions), locking/unlocking mechanisms, statistical // information, etc. +// define SharedStubId enum tags: wrong_method_id, etc + +#define SHARED_STUB_ID_ENUM_DECLARE(name, type) STUB_ID_NAME(name), +enum class SharedStubId :int { + NO_STUBID = -1, + SHARED_STUBS_DO(SHARED_STUB_ID_ENUM_DECLARE) + NUM_STUBIDS +}; +#undef SHARED_STUB_ID_ENUM_DECLARE + class SharedRuntime: AllStatic { friend class VMStructs; private: - // Shared stub locations + // Declare shared stub fields +#define SHARED_STUB_FIELD_DECLARE(name, type) \ + static type BLOB_FIELD_NAME(name); + SHARED_STUBS_DO(SHARED_STUB_FIELD_DECLARE) +#undef SHARED_STUB_FIELD_DECLARE - static RuntimeStub* _wrong_method_blob; - static RuntimeStub* _wrong_method_abstract_blob; - static RuntimeStub* _ic_miss_blob; - static RuntimeStub* _resolve_opt_virtual_call_blob; - static RuntimeStub* _resolve_virtual_call_blob; - static RuntimeStub* _resolve_static_call_blob; - - static DeoptimizationBlob* _deopt_blob; - - static SafepointBlob* _polling_page_vectors_safepoint_handler_blob; - static SafepointBlob* _polling_page_safepoint_handler_blob; - static SafepointBlob* _polling_page_return_handler_blob; +#ifdef ASSERT + static bool is_resolve_id(SharedStubId id) { + return (id == SharedStubId::wrong_method_id || + id == SharedStubId::wrong_method_abstract_id || + id == SharedStubId::ic_miss_id || + id == SharedStubId::resolve_opt_virtual_call_id || + id == SharedStubId::resolve_virtual_call_id || + id == SharedStubId::resolve_static_call_id); + } + static bool is_polling_page_id(SharedStubId id) { + return (id == SharedStubId::polling_page_vectors_safepoint_handler_id || + id == SharedStubId::polling_page_safepoint_handler_id || + id == SharedStubId::polling_page_return_handler_id); + } + static bool is_throw_id(SharedStubId id) { + return (id == SharedStubId::throw_AbstractMethodError_id || + id == SharedStubId::throw_IncompatibleClassChangeError_id || + id == SharedStubId::throw_NullPointerException_at_call_id || + id == SharedStubId::throw_StackOverflowError_id || + id == SharedStubId::throw_delayed_StackOverflowError_id); + } +#endif + // cont_doYieldStub is not yet folded into the general model for + // shared stub/blob handling. It is actually a specially generated + // native wrapper for a specific native method, as also is it's + // counterpart the continuation do_enter method. static nmethod* _cont_doYield_stub; - static RuntimeStub* _throw_AbstractMethodError_blob; - static RuntimeStub* _throw_IncompatibleClassChangeError_blob; - static RuntimeStub* _throw_NullPointerException_at_call_blob; - static RuntimeStub* _throw_StackOverflowError_blob; - static RuntimeStub* _throw_delayed_StackOverflowError_blob; - -#if INCLUDE_JFR - static RuntimeStub* _jfr_write_checkpoint_blob; - static RuntimeStub* _jfr_return_lease_blob; -#endif + // Stub names indexed by SharedStubId + static const char *_stub_names[]; #ifndef PRODUCT // Counters @@ -80,10 +101,9 @@ class SharedRuntime: AllStatic { #endif // !PRODUCT private: - enum { POLL_AT_RETURN, POLL_AT_LOOP, POLL_AT_VECTOR_LOOP }; - static SafepointBlob* generate_handler_blob(address call_ptr, int poll_type); - static RuntimeStub* generate_resolve_blob(address destination, const char* name); - static RuntimeStub* generate_throw_exception(const char* name, address runtime_entry); + static SafepointBlob* generate_handler_blob(SharedStubId id, address call_ptr); + static RuntimeStub* generate_resolve_blob(SharedStubId id, address destination); + static RuntimeStub* generate_throw_exception(SharedStubId id, address runtime_entry); public: static void generate_initial_stubs(void); static void generate_stubs(void); @@ -97,6 +117,11 @@ class SharedRuntime: AllStatic { static RuntimeStub* generate_jfr_return_lease(); #endif + static const char *stub_name(SharedStubId id) { + assert(id > SharedStubId::NO_STUBID && id < SharedStubId::NUM_STUBIDS, "stub id out of range"); + return _stub_names[(int)id]; + } + // max bytes for each dtrace string parameter enum { max_dtrace_string_size = 256 }; diff --git a/src/hotspot/share/runtime/stackOverflow.hpp b/src/hotspot/share/runtime/stackOverflow.hpp index b897c86d249..4734a6c6788 100644 --- a/src/hotspot/share/runtime/stackOverflow.hpp +++ b/src/hotspot/share/runtime/stackOverflow.hpp @@ -293,6 +293,16 @@ class StackOverflow { return _shadow_zone_safe_limit; } + address shadow_zone_growth_watermark() const { + assert(_shadow_zone_growth_watermark != nullptr, "Don't call this before the field is initialized."); + return _shadow_zone_growth_watermark; + } + + void set_shadow_zone_growth_watermark(address new_watermark) { + assert(_shadow_zone_growth_watermark != nullptr, "Don't call this before the field is initialized."); + _shadow_zone_growth_watermark = new_watermark; + } + void create_stack_guard_pages(); void remove_stack_guard_pages(); diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp new file mode 100644 index 00000000000..c9e946906f7 --- /dev/null +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_STUBDECLARATIONS_HPP +#define SHARE_RUNTIME_STUBDECLARATIONS_HPP + +#include "utilities/macros.hpp" + +// macros for generating definitions and declarations for shared, c1 +// and opto blob fields and associated stub ids + +// Different shared stubs can have different blob types and may +// include some JFR stubs +// +// n.b resolve, handler and throw stubs must remain grouped in the +// same order to allow id values to be range checked + +#if INCLUDE_JFR +// do_blob(name, type) +#define SHARED_JFR_STUBS_DO(do_blob) \ + do_blob(jfr_write_checkpoint, RuntimeStub*) \ + do_blob(jfr_return_lease, RuntimeStub*) \ + +#else +#define SHARED_JFR_STUBS_DO(do_blob) +#endif + +// do_blob(name, type) +#define SHARED_STUBS_DO(do_blob) \ + do_blob(deopt, DeoptimizationBlob*) \ + /* resolve stubs */ \ + do_blob(wrong_method, RuntimeStub*) \ + do_blob(wrong_method_abstract, RuntimeStub*) \ + do_blob(ic_miss, RuntimeStub*) \ + do_blob(resolve_opt_virtual_call, RuntimeStub*) \ + do_blob(resolve_virtual_call, RuntimeStub*) \ + do_blob(resolve_static_call, RuntimeStub*) \ + /* handler stubs */ \ + do_blob(polling_page_vectors_safepoint_handler, SafepointBlob*) \ + do_blob(polling_page_safepoint_handler, SafepointBlob*) \ + do_blob(polling_page_return_handler, SafepointBlob*) \ + /* throw stubs */ \ + do_blob(throw_AbstractMethodError, RuntimeStub*) \ + do_blob(throw_IncompatibleClassChangeError, RuntimeStub*) \ + do_blob(throw_NullPointerException_at_call, RuntimeStub*) \ + do_blob(throw_StackOverflowError, RuntimeStub*) \ + do_blob(throw_delayed_StackOverflowError, RuntimeStub*) \ + /* other stubs */ \ + SHARED_JFR_STUBS_DO(do_blob) \ + +// generate a stub id enum tag from a name + +#define STUB_ID_NAME(base) base##_id + +// generate a blob id enum tag from a name + +#define BLOB_ID_NAME(base) base##_id + +// generate a blob field name + +#define BLOB_FIELD_NAME(base) _##base##_blob + +#endif // SHARE_RUNTIME_STUBDECLARATIONS_HPP + diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 40c15e10c5a..483b96fccf3 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -563,6 +563,12 @@ \ nonstatic_field(DeoptimizationBlob, _unpack_offset, int) \ \ + /*****************************************************/ \ + /* UpcallStubs (NOTE: incomplete, but only a little) */ \ + /*****************************************************/ \ + \ + nonstatic_field(UpcallStub, _frame_data_offset, ByteSize) \ + \ /**************************************************/ \ /* NMethods (NOTE: incomplete, but only a little) */ \ /**************************************************/ \ @@ -1012,7 +1018,9 @@ nonstatic_field(AccessFlags, _flags, jint) \ nonstatic_field(elapsedTimer, _counter, jlong) \ nonstatic_field(elapsedTimer, _active, bool) \ - nonstatic_field(InvocationCounter, _counter, unsigned int) + nonstatic_field(InvocationCounter, _counter, unsigned int) \ + \ + nonstatic_field(UpcallStub::FrameData, jfa, JavaFrameAnchor) //-------------------------------------------------------------------------------- // VM_TYPES @@ -1306,6 +1314,7 @@ declare_type(nmethod, CodeBlob) \ declare_type(RuntimeStub, RuntimeBlob) \ declare_type(SingletonBlob, RuntimeBlob) \ + declare_type(UpcallStub, RuntimeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ @@ -1900,6 +1909,7 @@ declare_integer_type(BasicType) /* FIXME: wrong type (not integer) */ \ \ declare_integer_type(CompLevel) \ + declare_integer_type(ByteSize) \ JVMTI_ONLY(declare_toplevel_type(BreakpointInfo)) \ JVMTI_ONLY(declare_toplevel_type(BreakpointInfo*)) \ declare_toplevel_type(CodeBlob*) \ @@ -1948,6 +1958,7 @@ declare_type(FileMapInfo, CHeapObj) \ declare_toplevel_type(FileMapHeader) \ declare_toplevel_type(CDSFileMapRegion) \ + declare_toplevel_type(UpcallStub::FrameData) \ \ /************/ \ /* GC types */ \ diff --git a/src/java.base/aix/native/libnio/MappedMemoryUtils.c b/src/java.base/aix/native/libnio/MappedMemoryUtils.c index 5d0216cc251..e17ca2092af 100644 --- a/src/java.base/aix/native/libnio/MappedMemoryUtils.c +++ b/src/java.base/aix/native/libnio/MappedMemoryUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -46,9 +46,8 @@ static long calculate_number_of_pages_in_range(void* address, size_t len, size_t return numPages; } -JNIEXPORT jboolean JNICALL -Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, - jlong len, jlong numPages) +jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) { jboolean loaded = JNI_TRUE; int result = 0; @@ -93,8 +92,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, +void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, jlong len) { char *a = (char *)jlong_to_ptr(address); @@ -104,9 +102,8 @@ Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, } } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, - jlong len) +void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, + jlong len) { char *a = (char *)jlong_to_ptr(address); int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED); @@ -198,8 +195,7 @@ static int validate_msync_address(size_t address) return 0; } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, +void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, jlong address, jlong len) { void* a = (void *)jlong_to_ptr(address); @@ -218,3 +214,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed"); } } + +#define FD "Ljava/io/FileDescriptor;" + +static JNINativeMethod methods[] = { + {"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0}, + {"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0}, + {"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0}, + {"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0}, +}; + +JNIEXPORT void JNICALL +Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls) +{ + (*env)->RegisterNatives(env, cls, + methods, sizeof(methods)/sizeof(methods[0])); +} diff --git a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c index e3d811cfca6..d1397fe4546 100644 --- a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c +++ b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c @@ -97,25 +97,35 @@ jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, } } - // Get buffer size needed to read all processes - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; - if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) { - JNU_ThrowByNameWithLastError(env, - "java/lang/RuntimeException", "sysctl failed"); - return -1; - } + int errsysctl; + int maxRetries = 100; + void *buffer = NULL; + do { + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; + if (buffer != NULL) free(buffer); + // Get buffer size needed to read all processes + if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) { + JNU_ThrowByNameWithMessageAndLastError(env, + "java/lang/RuntimeException", "sysctl failed"); + return -1; + } - // Allocate buffer big enough for all processes - void *buffer = malloc(bufSize); - if (buffer == NULL) { - JNU_ThrowOutOfMemoryError(env, "malloc failed"); - return -1; - } + // Allocate buffer big enough for all processes; add a little + // bit of space to be able to hold a few more proc infos + // for processes started right after the first sysctl call + buffer = malloc(bufSize + 4 * sizeof(struct kinfo_proc)); + if (buffer == NULL) { + JNU_ThrowOutOfMemoryError(env, "malloc failed"); + return -1; + } - // Read process info for all processes - if (sysctl(mib, 4, buffer, &bufSize, NULL, 0) < 0) { - JNU_ThrowByNameWithLastError(env, - "java/lang/RuntimeException", "sysctl failed"); + // Read process info for all processes + errsysctl = sysctl(mib, 4, buffer, &bufSize, NULL, 0); + } while (errsysctl < 0 && errno == ENOMEM && maxRetries-- > 0); + + if (errsysctl < 0) { + JNU_ThrowByNameWithMessageAndLastError(env, + "java/lang/RuntimeException", "sysctl failed to get info about all processes"); free(buffer); return -1; } diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index f7fa0dbe96b..48ffeea5289 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -1247,7 +1247,7 @@ public Package getPackage() { * @return the fully qualified package name * * @since 9 - * @jls 6.7 Fully Qualified Names + * @jls 6.7 Fully Qualified Names and Canonical Names */ public String getPackageName() { String pn = this.packageName; @@ -1460,7 +1460,7 @@ private Class elementType() { * programming language and JVM modeling in core reflection * @since 1.1 * @jls 8.1.1 Class Modifiers - * @jls 9.1.1. Interface Modifiers + * @jls 9.1.1 Interface Modifiers * @jvms 4.1 The {@code ClassFile} Structure */ @IntrinsicCandidate @@ -1994,7 +1994,7 @@ public boolean isAnonymousClass() { * * @return {@code true} if and only if this class is a local class. * @since 1.5 - * @jls 14.3 Local Class Declarations + * @jls 14.3 Local Class and Interface Declarations */ public boolean isLocalClass() { return isLocalOrAnonymousClass() && @@ -2007,7 +2007,7 @@ public boolean isLocalClass() { * * @return {@code true} if and only if this class is a member class. * @since 1.5 - * @jls 8.5 Member Type Declarations + * @jls 8.5 Member Class and Interface Declarations */ public boolean isMemberClass() { return !isLocalOrAnonymousClass() && getDeclaringClass0() != null; @@ -2544,7 +2544,7 @@ public Constructor getConstructor(Class... parameterTypes) * * * @since 1.1 - * @jls 8.5 Member Type Declarations + * @jls 8.5 Member Class and Interface Declarations */ @CallerSensitive public Class[] getDeclaredClasses() throws SecurityException { diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 5817c37d6f6..fafa8895ee6 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -223,7 +223,7 @@ * or a fully qualified name as defined by * The Java Language Specification. * - * @jls 6.7 Fully Qualified Names + * @jls 6.7 Fully Qualified Names and Canonical Names * @jls 13.1 The Form of a Binary * @see #resolveClass(Class) * @since 1.0 @@ -2450,7 +2450,8 @@ static NativeLibrary loadLibrary(Class fromClass, String name) { * @param javaName the native method's declared name */ static long findNative(ClassLoader loader, Class clazz, String entryName, String javaName) { - long addr = findNativeInternal(loader, entryName); + NativeLibraries nativeLibraries = nativeLibrariesFor(loader); + long addr = nativeLibraries.find(entryName); if (addr != 0 && loader != null) { Reflection.ensureNativeAccess(clazz, clazz, javaName, true); } @@ -2462,11 +2463,11 @@ static long findNative(ClassLoader loader, Class clazz, String entryName, Str * to avoid a restricted check, as that check has already been performed when * obtaining the lookup. */ - static long findNativeInternal(ClassLoader loader, String entryName) { + static NativeLibraries nativeLibrariesFor(ClassLoader loader) { if (loader == null) { - return BootLoader.getNativeLibraries().find(entryName); + return BootLoader.getNativeLibraries(); } else { - return loader.libraries.find(entryName); + return loader.libraries; } } diff --git a/src/java.base/share/classes/java/lang/Double.java b/src/java.base/share/classes/java/lang/Double.java index 5f4c0b3f40f..9b11964d9e6 100644 --- a/src/java.base/share/classes/java/lang/Double.java +++ b/src/java.base/share/classes/java/lang/Double.java @@ -344,8 +344,8 @@ * 754 floating-point arithmetic follows a principled design and its * behavior is predictable on the Java platform. * - * @jls 4.2.3 Floating-Point Types, Formats, and Values - * @jls 4.2.4. Floating-Point Operations + * @jls 4.2.3 Floating-Point Types and Values + * @jls 4.2.4 Floating-Point Operations * @jls 15.21.1 Numerical Equality Operators == and != * @jls 15.20.1 Numerical Comparison Operators {@code <}, {@code <=}, {@code >}, and {@code >=} * diff --git a/src/java.base/share/classes/java/lang/Record.java b/src/java.base/share/classes/java/lang/Record.java index dba72c6ebfb..808bc7cc9cd 100644 --- a/src/java.base/share/classes/java/lang/Record.java +++ b/src/java.base/share/classes/java/lang/Record.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -84,7 +84,7 @@ * See {@link Class#isRecord()} and {@link Class#getRecordComponents()} for more details. * * @spec serialization/index.html Java Object Serialization Specification - * @jls 8.10 Record Types + * @jls 8.10 Record Classes * @since 16 */ public abstract class Record { diff --git a/src/java.base/share/classes/java/lang/StackWalker.java b/src/java.base/share/classes/java/lang/StackWalker.java index aab9c6c28d8..8a39c465c2b 100644 --- a/src/java.base/share/classes/java/lang/StackWalker.java +++ b/src/java.base/share/classes/java/lang/StackWalker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -170,7 +170,7 @@ public default MethodType getMethodType() { * * @see MethodType#fromMethodDescriptorString(String, ClassLoader) * @see MethodType#toMethodDescriptorString() - * @jvms 4.3.3 Method Descriptor + * @jvms 4.3.3 Method Descriptors * * @since 10 */ diff --git a/src/java.base/share/classes/java/lang/StringCoding.java b/src/java.base/share/classes/java/lang/StringCoding.java index 293fbdb78dc..c02af28c37d 100644 --- a/src/java.base/share/classes/java/lang/StringCoding.java +++ b/src/java.base/share/classes/java/lang/StringCoding.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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 @@ -34,6 +35,45 @@ class StringCoding { private StringCoding() { } + /** + * Count the number of leading non-zero ascii chars in the range. + */ + public static int countNonZeroAscii(String s) { + byte[] value = s.value(); + if (s.isLatin1()) { + return countNonZeroAsciiLatin1(value, 0, value.length); + } else { + return countNonZeroAsciiUTF16(value, 0, s.length()); + } + } + + /** + * Count the number of non-zero ascii chars in the range. + */ + public static int countNonZeroAsciiLatin1(byte[] ba, int off, int len) { + int limit = off + len; + for (int i = off; i < limit; i++) { + if (ba[i] <= 0) { + return i - off; + } + } + return len; + } + + /** + * Count the number of leading non-zero ascii chars in the range. + */ + public static int countNonZeroAsciiUTF16(byte[] ba, int off, int strlen) { + int limit = off + strlen; + for (int i = off; i < limit; i++) { + char c = StringUTF16.charAt(ba, i); + if (c == 0 || c > 0x7F) { + return i - off; + } + } + return strlen; + } + public static boolean hasNegatives(byte[] ba, int off, int len) { return countPositives(ba, off, len) != len; } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 3c25ad3720d..930b6b7f611 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -65,11 +65,13 @@ import java.util.ResourceBundle; import java.util.Set; import java.util.WeakHashMap; +import java.util.concurrent.Executor; import java.util.function.Supplier; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; import jdk.internal.javac.Restricted; +import jdk.internal.loader.NativeLibraries; import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; import jdk.internal.misc.Blocker; import jdk.internal.misc.CarrierThreadLocal; @@ -2569,6 +2571,9 @@ public Stream layers(ClassLoader loader) { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } + public int countNonZeroAscii(String s) { + return StringCoding.countNonZeroAscii(s); + } public String newStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { return String.newStringNoRepl(bytes, cs); } @@ -2638,6 +2643,14 @@ public Object stringConcat1(String[] constants) { return new StringConcatHelper.Concat1(constants); } + public byte stringInitCoder() { + return String.COMPACT_STRINGS ? String.LATIN1 : String.UTF16; + } + + public byte stringCoder(String str) { + return str.coder(); + } + public int getCharsLatin1(long i, int index, byte[] buf) { return StringLatin1.getChars(i, index, buf); } @@ -2659,8 +2672,8 @@ public Object classData(Class c) { } @Override - public long findNative(ClassLoader loader, String entry) { - return ClassLoader.findNativeInternal(loader, entry); + public NativeLibraries nativeLibrariesFor(ClassLoader loader) { + return ClassLoader.nativeLibrariesFor(loader); } @Override @@ -2758,6 +2771,10 @@ public void unparkVirtualThread(Thread thread) { } } + public Executor virtualThreadDefaultScheduler() { + return VirtualThread.defaultScheduler(); + } + public StackWalker newStackWalkerInstance(Set options, ContinuationScope contScope, Continuation continuation) { diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 4dac486bee4..07b3c7c9bd2 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -457,19 +457,20 @@ public static void yield() { * Called before sleeping to create a jdk.ThreadSleep event. */ private static ThreadSleepEvent beforeSleep(long nanos) { - ThreadSleepEvent event = null; - if (ThreadSleepEvent.isTurnedOn()) { - try { - event = new ThreadSleepEvent(); + try { + ThreadSleepEvent event = new ThreadSleepEvent(); + if (event.isEnabled()) { event.time = nanos; event.begin(); - } catch (OutOfMemoryError e) { - event = null; + return event; } + } catch (OutOfMemoryError e) { + // ignore } - return event; + return null; } + /** * Called after sleeping to commit the jdk.ThreadSleep event. */ diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index da05e77f12b..6eb20fa9e2e 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -142,6 +142,14 @@ final class VirtualThread extends BaseVirtualThread { // termination object when joining, created lazily if needed private volatile CountDownLatch termination; + + /** + * Returns the default scheduler. + */ + static Executor defaultScheduler() { + return DEFAULT_SCHEDULER; + } + /** * Returns the continuation scope used for virtual threads. */ diff --git a/src/java.base/share/classes/java/lang/constant/PackageDesc.java b/src/java.base/share/classes/java/lang/constant/PackageDesc.java index c354cafae3c..2798d69d6da 100644 --- a/src/java.base/share/classes/java/lang/constant/PackageDesc.java +++ b/src/java.base/share/classes/java/lang/constant/PackageDesc.java @@ -51,7 +51,7 @@ public sealed interface PackageDesc * @throws NullPointerException if the argument is {@code null} * @throws IllegalArgumentException if the name string is not in the * correct format - * @jls 6.5.3 Module Names and Package Names + * @jls 6.5.3 Meaning of Module Names and Package Names * @see PackageDesc#ofInternalName(String) */ static PackageDesc of(String name) { diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 8f171fd8bfb..38fd36bbb15 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1570,8 +1570,9 @@ static MemorySegment ofAddress(long address) { @ForceInline static void copy(MemorySegment srcSegment, long srcOffset, MemorySegment dstSegment, long dstOffset, long bytes) { - copy(srcSegment, ValueLayout.JAVA_BYTE, srcOffset, - dstSegment, ValueLayout.JAVA_BYTE, dstOffset, + + AbstractMemorySegmentImpl.copy((AbstractMemorySegmentImpl) srcSegment, srcOffset, + (AbstractMemorySegmentImpl) dstSegment, dstOffset, bytes); } diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java index c6e4443b570..d0dc60b3f77 100644 --- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java +++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java @@ -31,6 +31,7 @@ import jdk.internal.foreign.Utils; import jdk.internal.javac.Restricted; import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.loader.NativeLibraries; import jdk.internal.loader.NativeLibrary; import jdk.internal.loader.RawNativeLibraries; import jdk.internal.reflect.CallerSensitive; @@ -256,7 +257,8 @@ static SymbolLookup loaderLookup() { if (Utils.containsNullChars(name)) return Optional.empty(); JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess(); // note: ClassLoader::findNative supports a null loader - long addr = javaLangAccess.findNative(loader, name); + NativeLibraries nativeLibraries = javaLangAccess.nativeLibrariesFor(loader); + long addr = nativeLibraries.find(name); return addr == 0L ? Optional.empty() : Optional.of(MemorySegment.ofAddress(addr) diff --git a/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java b/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java index 11e9b720421..6e0cc994481 100644 --- a/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java +++ b/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java @@ -99,7 +99,7 @@ else if (!info.getClass().isArray()) { // with empty constant arguments? if (isStringConcatFactoryBSM(bootstrapMethod.type())) { result = (CallSite)bootstrapMethod - .invokeExact(caller, name, (MethodType)type, + .invokeBasic(caller, name, (MethodType)type, (String)info, new Object[0]); } else { info = maybeReBox(info); @@ -131,23 +131,19 @@ else if (info.getClass() == int[].class) { MethodType bsmType = bootstrapMethod.type(); if (isLambdaMetafactoryIndyBSM(bsmType) && argv.length == 3) { result = (CallSite)bootstrapMethod - .invokeExact(caller, name, (MethodType)type, (MethodType)argv[0], - (MethodHandle)argv[1], (MethodType)argv[2]); - } else if (isLambdaMetafactoryCondyBSM(bsmType) && argv.length == 3) { - result = bootstrapMethod - .invokeExact(caller, name, (Class)type, (MethodType)argv[0], + .invokeBasic(caller, name, (MethodType)type, (MethodType)argv[0], (MethodHandle)argv[1], (MethodType)argv[2]); } else if (isStringConcatFactoryBSM(bsmType) && argv.length >= 1) { String recipe = (String)argv[0]; Object[] shiftedArgs = Arrays.copyOfRange(argv, 1, argv.length); maybeReBoxElements(shiftedArgs); - result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, recipe, shiftedArgs); + result = (CallSite)bootstrapMethod.invokeBasic(caller, name, (MethodType)type, recipe, shiftedArgs); } else if (isLambdaMetafactoryAltMetafactoryBSM(bsmType)) { maybeReBoxElements(argv); - result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, argv); + result = (CallSite)bootstrapMethod.invokeBasic(caller, name, (MethodType)type, argv); } else if (isObjectMethodsBootstrapBSM(bsmType)) { MethodHandle[] mhs = Arrays.copyOfRange(argv, 2, argv.length, MethodHandle[].class); - result = bootstrapMethod.invokeExact(caller, name, (TypeDescriptor)type, (Class)argv[0], (String)argv[1], mhs); + result = bootstrapMethod.invokeBasic(caller, name, (TypeDescriptor)type, (Class)argv[0], (String)argv[1], mhs); } else { maybeReBoxElements(argv); if (type instanceof Class c) { @@ -252,9 +248,6 @@ private static Object invokeWithManyArguments(MethodHandle bootstrapMethod, Look private static final MethodType OBJECT_METHODS_MT = MethodType.methodType(Object.class, Lookup.class, String.class, TypeDescriptor.class, Class.class, String.class, MethodHandle[].class); - private static final MethodType LMF_CONDY_MT = MethodType.methodType(Object.class, - Lookup.class, String.class, Class.class, MethodType.class, MethodHandle.class, MethodType.class); - private static final MethodType SCF_MT = MethodType.methodType(CallSite.class, Lookup.class, String.class, MethodType.class, String.class, Object[].class); @@ -267,15 +260,6 @@ private static boolean isStringConcatFactoryBSM(MethodType bsmType) { return bsmType == SCF_MT; } - /** - * @return true iff the BSM method type exactly matches - * {@link java.lang.invoke.LambdaMetafactory#metafactory( - * MethodHandles.Lookup,String,Class,MethodType,MethodHandle,MethodType)} - */ - private static boolean isLambdaMetafactoryCondyBSM(MethodType bsmType) { - return bsmType == LMF_CONDY_MT; - } - /** * @return true iff the BSM method type exactly matches * {@link java.lang.invoke.LambdaMetafactory#metafactory( diff --git a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java index 1e3f465f97d..a9497502ec6 100644 --- a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java +++ b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java @@ -563,7 +563,7 @@ private static byte[] generateCodeBytesForLFs(String className, String[] names, .withSuperclass(InvokerBytecodeGenerator.INVOKER_SUPER_DESC) .with(SourceFileAttribute.of(className.substring(className.lastIndexOf('/') + 1))); for (int i = 0; i < forms.length; i++) { - new InvokerBytecodeGenerator(className, names[i], forms[i], forms[i].methodType()).addMethod(clb); + new InvokerBytecodeGenerator(className, names[i], forms[i], forms[i].methodType()).addMethod(clb, false); } }); } diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 24c97d7f7dc..23893cb3c26 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -97,7 +97,8 @@ private final String[] argNames; // Generated names for the constructor arguments private final ClassDesc[] argDescs; // Type descriptors for the constructor arguments private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" - private final ClassDesc lambdaClassDesc; // Type descriptor for the generated class "X$$Lambda$1" + private final ConstantPoolBuilder pool = ConstantPoolBuilder.of(); + private final ClassEntry lambdaClassEntry; // Class entry for the generated class "X$$Lambda$1" private final boolean useImplMethodHandle; // use MethodHandle invocation instead of symbolic bytecode invocation /** @@ -157,9 +158,8 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, implMethodName = implInfo.getName(); implMethodDesc = methodDesc(implInfo.getMethodType()); constructorType = factoryType.changeReturnType(Void.TYPE); - constructorTypeDesc = methodDesc(constructorType); lambdaClassName = lambdaClassName(targetClass); - lambdaClassDesc = ClassDesc.ofInternalName(lambdaClassName); + lambdaClassEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(ConstantUtils.concat("L", lambdaClassName, ";"))); // If the target class invokes a protected method inherited from a // superclass in a different package, or does 'invokespecial', the // lambda class has no access to the resolved method, or does @@ -183,6 +183,7 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, argNames = EMPTY_STRING_ARRAY; argDescs = EMPTY_CLASSDESC_ARRAY; } + constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs); } private static String lambdaClassName(Class targetClass) { @@ -191,7 +192,7 @@ private static String lambdaClassName(Class targetClass) { // use the original class name name = name.replace('/', '_'); } - return name.replace('.', '/') + "$$Lambda"; + return name.replace('.', '/').concat("$$Lambda"); } /** @@ -221,7 +222,7 @@ CallSite buildCallSite() throws LambdaConversionException { MethodHandle mh = caller.findConstructor(innerClass, constructorType); if (factoryType.parameterCount() == 0) { // In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance - Object inst = mh.asType(methodType(Object.class)).invokeExact(); + Object inst = mh.invokeBasic(); return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst)); } else { return new ConstantCallSite(mh.asType(factoryType)); @@ -303,7 +304,7 @@ private Class generateInnerClass() throws LambdaConversionException { interfaces = List.copyOf(itfs); } final boolean finalAccidentallySerializable = accidentallySerializable; - final byte[] classBytes = ClassFile.of().build(lambdaClassDesc, new Consumer() { + final byte[] classBytes = ClassFile.of().build(lambdaClassEntry, pool, new Consumer() { @Override public void accept(ClassBuilder clb) { clb.withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC) @@ -369,10 +370,10 @@ private void generateClassInitializer(ClassBuilder clb) { @Override public void accept(CodeBuilder cob) { assert factoryType.parameterCount() == 0; - cob.new_(lambdaClassDesc) + cob.new_(lambdaClassEntry) .dup() - .invokespecial(lambdaClassDesc, INIT_NAME, constructorTypeDesc) - .putstatic(lambdaClassDesc, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor) + .invokespecial(pool.methodRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(INIT_NAME, constructorTypeDesc))) + .putstatic(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor))) .return_(); } }); @@ -394,7 +395,7 @@ public void accept(CodeBuilder cob) { cob.aload(0); Class argType = factoryType.parameterType(i); cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i)); - cob.putfield(lambdaClassDesc, argNames[i], argDescs[i]); + cob.putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); } cob.return_(); } @@ -446,7 +447,7 @@ public void accept(CodeBuilder cob) { cob.dup() .loadConstant(i) .aload(0) - .getfield(lambdaClassDesc, argNames[i], argDescs[i]); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); TypeConvertingMethodAdapter.boxIfTypePrimitive(cob, TypeKind.from(argDescs[i])); cob.aastore(); } @@ -505,7 +506,7 @@ public void accept(CodeBuilder cob) { } for (int i = 0; i < argNames.length; i++) { cob.aload(0) - .getfield(lambdaClassDesc, argNames[i], argDescs[i]); + .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i]))); } convertArgumentTypes(cob, methodType); diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 7e58a862211..c69913ba6cd 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -32,6 +32,9 @@ import java.lang.classfile.*; import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.classfile.attribute.SourceFileAttribute; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.FieldRefEntry; import java.lang.classfile.instruction.SwitchCase; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; @@ -57,6 +60,8 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; +import static jdk.internal.constant.ConstantUtils.concat; +import static jdk.internal.constant.ConstantUtils.validateInternalClassName; /** * Code generation backend for LambdaForm. @@ -67,6 +72,7 @@ class InvokerBytecodeGenerator { /** Define class names for convenience. */ private static final ClassDesc CD_CasesHolder = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$CasesHolder;"); private static final ClassDesc CD_DirectMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/DirectMethodHandle;"); + private static final ClassDesc CD_MemberName = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MemberName;"); private static final ClassDesc CD_MethodHandleImpl = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl;"); private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;"); private static final ClassDesc CD_LambdaForm_Name = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Name;"); @@ -89,7 +95,8 @@ class InvokerBytecodeGenerator { /** Name of new class */ private final String name; private final String className; - private final ClassDesc classDesc; + private final ConstantPoolBuilder pool = ConstantPoolBuilder.of(); + private final ClassEntry classEntry; private final LambdaForm lambdaForm; private final String invokerName; @@ -126,7 +133,8 @@ private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize, } this.name = name; this.className = CLASS_PREFIX.concat(name); - this.classDesc = ClassDesc.ofInternalName(className); + validateInternalClassName(name); + this.classEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(concat("L", className, ";"))); this.lambdaForm = lambdaForm; this.invokerName = invokerName; this.invokerType = invokerType; @@ -142,8 +150,8 @@ private InvokerBytecodeGenerator(String name, String invokerName, MethodType inv // Create an array to map name indexes to locals indexes. localsMap[0] = 0; // localsMap has at least one element for (int i = 1, index = 0; i < localsMap.length; i++) { - Wrapper w = Wrapper.forBasicType(mt.parameterType(i - 1)); - index += w.stackSlots(); + Class cl = mt.parameterType(i - 1); + index += (cl == long.class || cl == double.class) ? 2 : 1; localsMap[i] = index; } } @@ -192,37 +200,12 @@ private static String makeDumpableClassName(String className) { return buf.toString(); } - static class ClassData { - final String name; - final ClassDesc desc; - final Object value; - - ClassData(String name, ClassDesc desc, Object value) { - this.name = name; - this.desc = desc; - this.value = value; - } - - public String name() { return name; } - public String toString() { - return name + ",value="+value; - } - } - - String classData(Object arg) { - ClassDesc desc; - if (arg instanceof Class) { - desc = CD_Class; - } else if (arg instanceof MethodHandle) { - desc = CD_MethodHandle; - } else if (arg instanceof LambdaForm) { - desc = CD_LambdaForm; - } else { - desc = CD_Object; - } + record ClassData(FieldRefEntry field, Object value) {} + FieldRefEntry classData(ClassFileBuilder cfb, Object arg, ClassDesc desc) { // unique static variable name String name; + List classData = this.classData; if (dumper().isEnabled()) { Class c = arg.getClass(); while (c.isArray()) { @@ -232,9 +215,9 @@ String classData(Object arg) { } else { name = "_D_" + classData.size(); } - ClassData cd = new ClassData(name, desc, arg); - classData.add(cd); - return name; + var field = pool.fieldRefEntry(classEntry, pool.nameAndTypeEntry(name, desc)); + classData.add(new ClassData(field, arg)); + return field; } /** @@ -263,10 +246,10 @@ private static MemberName resolveInvokerMember(Class invokerClass, String nam */ private byte[] classFileSetup(Consumer config) { try { - return ClassFile.of().build(classDesc, new Consumer<>() { + return ClassFile.of().build(classEntry, pool, new Consumer<>() { @Override public void accept(ClassBuilder clb) { - clb.withFlags(ACC_FINAL | ACC_SUPER) + clb.withFlags(ACC_ABSTRACT | ACC_SUPER) .withSuperclass(INVOKER_SUPER_DESC) .with(SourceFileAttribute.of(clb.constantPool().utf8Entry(SOURCE_PREFIX + name))); config.accept(clb); @@ -292,15 +275,16 @@ private void methodSetup(ClassBuilder clb, Consumer confi */ private Object classDataValues() { final List cd = classData; - return switch (cd.size()) { + int size = cd.size(); + return switch (size) { case 0 -> null; // special case (classData is not used by ) case 1 -> cd.get(0).value; // special case (single object) case 2 -> List.of(cd.get(0).value, cd.get(1).value); case 3 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value); case 4 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value, cd.get(3).value); default -> { - Object[] data = new Object[classData.size()]; - for (int i = 0; i < classData.size(); i++) { + Object[] data = new Object[size]; + for (int i = 0; i < size; i++) { data[i] = classData.get(i).value; } yield List.of(data); @@ -312,36 +296,42 @@ private Object classDataValues() { * to initialize the static final fields with the live class data * LambdaForms can't use condy due to bootstrapping issue. */ - static void clinit(ClassBuilder clb, ClassDesc classDesc, List classData) { + static void clinit(ClassBuilder clb, ClassEntry classEntry, List classData) { if (classData.isEmpty()) return; - for (ClassData p : classData) { - // add the static field - clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL); - } - clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new Consumer<>() { @Override public void accept(CodeBuilder cob) { - cob.loadConstant(classDesc) + cob.ldc(classEntry) .invokestatic(CD_MethodHandles, "classData", MTD_Object_Class); - if (classData.size() == 1) { - ClassData p = classData.get(0); - cob.checkcast(p.desc) - .putstatic(classDesc, p.name, p.desc); + int size = classData.size(); + if (size == 1) { + var field = classData.getFirst().field; + // add the static field + clb.withField(field.name(), field.type(), ACC_STATIC | ACC_FINAL); + + var ft = field.typeSymbol(); + if (ft != CD_Object) + cob.checkcast(ft); + cob.putstatic(field); } else { cob.checkcast(CD_List) .astore(0); int index = 0; var listGet = cob.constantPool().interfaceMethodRefEntry(CD_List, "get", MTD_Object_int); - for (ClassData p : classData) { + for (int i = 0; i < size; i++) { + var field = classData.get(i).field; + // add the static field + clb.withField(field.name(), field.type(), ACC_STATIC | ACC_FINAL); // initialize the static field cob.aload(0) .loadConstant(index++) - .invokeinterface(listGet) - .checkcast(p.desc) - .putstatic(classDesc, p.name, p.desc); + .invokeinterface(listGet); + var ft = field.typeSymbol(); + if (ft != CD_Object) + cob.checkcast(ft); + cob.putstatic(field); } } cob.return_(); @@ -359,8 +349,6 @@ private void emitStoreInsn(CodeBuilder cob, TypeKind type, int index) { /** * Emit a boxing call. - * - * @param wrapper primitive type class to box. */ private void emitBoxing(CodeBuilder cob, TypeKind tk) { TypeConvertingMethodAdapter.box(cob, tk); @@ -368,8 +356,6 @@ private void emitBoxing(CodeBuilder cob, TypeKind tk) { /** * Emit an unboxing call (plus preceding checkcast). - * - * @param wrapper wrapper type class to unbox. */ private void emitUnboxing(CodeBuilder cob, TypeKind target) { switch (target) { @@ -438,7 +424,7 @@ private void emitReferenceCast(CodeBuilder cob, Class cls, Object arg) { ClassDesc sig = classDesc(cls); cob.checkcast(sig); } else { - cob.getstatic(classDesc, classData(cls), CD_Class) + cob.getstatic(classData(cob, cls, CD_Class)) .swap() .invokevirtual(CD_Class, "cast", MTD_Object_Object); if (Object[].class.isAssignableFrom(cls)) @@ -538,45 +524,42 @@ private boolean checkActualReceiver(CodeBuilder cob) { static final Annotation INJECTEDPROFILE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/InjectedProfile;")); static final Annotation LF_COMPILED = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Compiled;")); + // Suppress method in backtraces displayed to the user, mark this method as + // a compiled LambdaForm, then either force or prohibit inlining. + public static final RuntimeVisibleAnnotationsAttribute LF_DONTINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, DONTINLINE); + public static final RuntimeVisibleAnnotationsAttribute LF_FORCEINLINE_ANNOTATIONS = RuntimeVisibleAnnotationsAttribute.of(HIDDEN, LF_COMPILED, FORCEINLINE); + /** * Generate an invoker method for the passed {@link LambdaForm}. */ private byte[] generateCustomizedCodeBytes() { - final byte[] classFile = classFileSetup(new Consumer() { + final byte[] classFile = classFileSetup(new Consumer<>() { @Override public void accept(ClassBuilder clb) { - addMethod(clb); - clinit(clb, classDesc, classData); + addMethod(clb, true); + clinit(clb, classEntry, classData); bogusMethod(clb, lambdaForm); } }); return classFile; } - void addMethod(ClassBuilder clb) { - methodSetup(clb, new Consumer() { + void addMethod(ClassBuilder clb, boolean alive) { + methodSetup(clb, new Consumer<>() { @Override public void accept(MethodBuilder mb) { - List annotations = new ArrayList<>(3); - - // Suppress this method in backtraces displayed to the user. - annotations.add(HIDDEN); - - // Mark this method as a compiled LambdaForm - annotations.add(LF_COMPILED); - if (lambdaForm.forceInline) { - // Force inlining of this invoker method. - annotations.add(FORCEINLINE); + mb.accept(LF_FORCEINLINE_ANNOTATIONS); } else { - annotations.add(DONTINLINE); + mb.accept(LF_DONTINLINE_ANNOTATIONS); } - mb.accept(RuntimeVisibleAnnotationsAttribute.of(annotations)); - classData(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled. + if (alive) { + classData(mb, lambdaForm, CD_LambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled. + } - mb.withCode(new Consumer() { + mb.withCode(new Consumer<>() { @Override public void accept(CodeBuilder cob) { if (lambdaForm.customized != null) { @@ -584,8 +567,7 @@ public void accept(CodeBuilder cob) { // receiver MethodHandle (at slot #0) with an embedded constant and use it instead. // It enables more efficient code generation in some situations, since embedded constants // are compile-time constants for JIT compiler. - cob.getstatic(classDesc, classData(lambdaForm.customized), CD_MethodHandle) - .checkcast(CD_MethodHandle); + cob.getstatic(classData(cob, lambdaForm.customized, CD_MethodHandle)); assert(checkActualReceiver(cob)); // expects MethodHandle on top of the stack cob.astore(0); } @@ -718,7 +700,7 @@ void emitInvoke(CodeBuilder cob, Name name) { // push receiver MethodHandle target = name.function.resolvedHandle(); assert(target != null) : name.exprString(); - cob.getstatic(classDesc, classData(target), CD_MethodHandle); + cob.getstatic(classData(cob, target, CD_MethodHandle)); emitReferenceCast(cob, MethodHandle.class, target); } else { // load receiver @@ -1443,7 +1425,7 @@ private void emitPushArgument(CodeBuilder cob, Class ptype, Object arg) { if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) { cob.loadConstant((ConstantDesc)arg); } else { - cob.getstatic(classDesc, classData(arg), CD_Object); + cob.getstatic(classData(cob, arg, CD_Object)); emitImplicitConversion(cob, L_TYPE, ptype, arg); } } @@ -1522,10 +1504,10 @@ static MemberName generateLambdaFormInterpreterEntryPoint(MethodType mt) { } private byte[] generateLambdaFormInterpreterEntryPointBytes() { - final byte[] classFile = classFileSetup(new Consumer() { + final byte[] classFile = classFileSetup(new Consumer<>() { @Override public void accept(ClassBuilder clb) { - methodSetup(clb, new Consumer() { + methodSetup(clb, new Consumer<>() { @Override public void accept(MethodBuilder mb) { @@ -1534,7 +1516,7 @@ public void accept(MethodBuilder mb) { DONTINLINE // Don't inline the interpreter entry. ))); - mb.withCode(new Consumer() { + mb.withCode(new Consumer<>() { @Override public void accept(CodeBuilder cob) { // create parameter array @@ -1572,7 +1554,7 @@ public void accept(CodeBuilder cob) { }); } }); - clinit(clb, classDesc, classData); + clinit(clb, classEntry, classData); bogusMethod(clb, invokerType); } }); @@ -1591,10 +1573,10 @@ static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) { private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) { MethodType dstType = typeForm.erasedType(); - final byte[] classFile = classFileSetup(new Consumer() { + final byte[] classFile = classFileSetup(new Consumer<>() { @Override public void accept(ClassBuilder clb) { - methodSetup(clb, new Consumer() { + methodSetup(clb, new Consumer<>() { @Override public void accept(MethodBuilder mb) { @@ -1603,7 +1585,7 @@ public void accept(MethodBuilder mb) { FORCEINLINE // Force inlining of this invoker method. ))); - mb.withCode(new Consumer() { + mb.withCode(new Consumer<>() { @Override public void accept(CodeBuilder cob) { // Load receiver @@ -1648,7 +1630,7 @@ public void accept(CodeBuilder cob) { }); } }); - clinit(clb, classDesc, classData); + clinit(clb, classEntry, classData); bogusMethod(clb, dstType); } }); @@ -1674,10 +1656,12 @@ public void accept(CodeBuilder cob) { static ClassDesc classDesc(Class cls) { // assert(VerifyAccess.isTypeVisible(cls, Object.class)) : cls.getName(); - return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor() - : cls == MethodHandle.class ? CD_MethodHandle + return cls == MethodHandle.class ? CD_MethodHandle : cls == DirectMethodHandle.class ? CD_DirectMethodHandle : cls == Object.class ? CD_Object + : cls == MemberName.class ? CD_MemberName + : cls == MethodType.class ? CD_MethodType + : cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor() : ReferenceClassDescImpl.ofValidated(cls.descriptorString()); } diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index 342cbbe77e5..0132cc6edf5 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -1555,6 +1555,7 @@ private static boolean typesMatch(BasicType parameterType, Object object) { * Return -1 if the name is not used. */ int lastUseIndex(Name n) { + Object[] arguments = this.arguments; if (arguments == null) return -1; for (int i = arguments.length; --i >= 0; ) { if (arguments[i] == n) return i; @@ -1562,21 +1563,6 @@ int lastUseIndex(Name n) { return -1; } - /** Return the number of occurrences of n in the argument array. - * Return 0 if the name is not used. - */ - int useCount(Name n) { - int count = 0; - if (arguments != null) { - for (Object argument : arguments) { - if (argument == n) { - count++; - } - } - } - return count; - } - public boolean equals(Name that) { if (this == that) return true; if (isParam()) @@ -1618,8 +1604,16 @@ int lastUseIndex(Name n) { int useCount(Name n) { int count = (result == n.index) ? 1 : 0; int i = Math.max(n.index + 1, arity); + Name[] names = this.names; while (i < names.length) { - count += names[i++].useCount(n); + Object[] arguments = names[i++].arguments; + if (arguments != null) { + for (Object argument : arguments) { + if (argument == n) { + count++; + } + } + } } return count; } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 0cb77f632b3..30c8ee03601 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -2206,7 +2206,7 @@ public Lookup defineHiddenClass(byte[] bytes, boolean initialize, ClassOption... * @jvms 5.3.5 Deriving a {@code Class} from a {@code class} File Representation * @jvms 5.4 Linking * @jvms 5.5 Initialization - * @jls 12.7 Unloading of Classes and Interface + * @jls 12.7 Unloading of Classes and Interfaces */ public Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, ClassOption... options) throws IllegalAccessException diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 44a4ef7b020..ab429899d30 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -119,12 +119,16 @@ */ public final class StringConcatFactory { private static final int HIGH_ARITY_THRESHOLD; + private static final int CACHE_THRESHOLD; private static final int FORCE_INLINE_THRESHOLD; static { String highArity = VM.getSavedProperty("java.lang.invoke.StringConcat.highArityThreshold"); HIGH_ARITY_THRESHOLD = highArity != null ? Integer.parseInt(highArity) : 0; + String cacheThreshold = VM.getSavedProperty("java.lang.invoke.StringConcat.cacheThreshold"); + CACHE_THRESHOLD = cacheThreshold != null ? Integer.parseInt(cacheThreshold) : 256; + String inlineThreshold = VM.getSavedProperty("java.lang.invoke.StringConcat.inlineThreshold"); FORCE_INLINE_THRESHOLD = inlineThreshold != null ? Integer.parseInt(inlineThreshold) : 16; } @@ -1179,26 +1183,35 @@ private static MethodType erasedArgs(MethodType args) { * int arg0, long arg1, boolean arg2, char arg3, String arg5) * */ - private static MethodTypeDesc prependArgs(MethodType concatArgs) { + private static MethodTypeDesc prependArgs(MethodType concatArgs, boolean staticConcat) { int parameterCount = concatArgs.parameterCount(); - var paramTypes = new ClassDesc[parameterCount + 4]; + int prefixArgs = staticConcat ? 3 : 4; + var paramTypes = new ClassDesc[parameterCount + prefixArgs]; paramTypes[0] = CD_int; // length paramTypes[1] = CD_byte; // coder paramTypes[2] = CD_Array_byte; // buff - paramTypes[3] = CD_Array_String; // constants + + if (!staticConcat) { + paramTypes[3] = CD_Array_String; // constants + } for (int i = 0; i < parameterCount; i++) { var cl = concatArgs.parameterType(i); - paramTypes[i + 4] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); + paramTypes[i + prefixArgs] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); } return MethodTypeDescImpl.ofValidated(CD_int, paramTypes); } /** * Construct the MethodType of the coder method. The first parameter is the initialized coder. - * Only parameter types which can be UTF16 are added. Returns null if no such parameter exists. + * Only parameter types which can be UTF16 are added. + * Returns null if no such parameter exists or CompactStrings is off. */ private static MethodTypeDesc coderArgsIfMaybeUTF16(MethodType concatArgs) { + if (JLA.stringInitCoder() != 0) { + return null; + } + int parameterCount = concatArgs.parameterCount(); int maybeUTF16Count = 0; @@ -1242,39 +1255,49 @@ private static MethodHandle generate(Lookup lookup, MethodType args, String[] co lookup = STR_LOOKUP; final MethodType concatArgs = erasedArgs(args); - // 1 argment use built-in method + // 1 argument use built-in method if (args.parameterCount() == 1) { Object concat1 = JLA.stringConcat1(constants); var handle = lookup.findVirtual(concat1.getClass(), METHOD_NAME, concatArgs); return handle.bindTo(concat1); } - var weakConstructorHandle = CACHE.get(concatArgs); - if (weakConstructorHandle != null) { - MethodHandlePair handlePair = weakConstructorHandle.get(); - if (handlePair != null) { - try { - var instance = handlePair.constructor.invoke(constants); - return handlePair.concatenator.bindTo(instance); - } catch (Throwable e) { - throw new StringConcatException("Exception while utilizing the hidden class", e); + boolean forceInline = concatArgs.parameterCount() < FORCE_INLINE_THRESHOLD; + boolean staticConcat = concatArgs.parameterCount() >= CACHE_THRESHOLD; + + if (!staticConcat) { + var weakConstructorHandle = CACHE.get(concatArgs); + if (weakConstructorHandle != null) { + MethodHandlePair handlePair = weakConstructorHandle.get(); + if (handlePair != null) { + try { + var instance = handlePair.constructor.invokeBasic((Object)constants); + return handlePair.concatenator.bindTo(instance); + } catch (Throwable e) { + throw new StringConcatException("Exception while utilizing the hidden class", e); + } } } } + MethodTypeDesc lengthArgs = lengthArgs(concatArgs), coderArgs = coderArgsIfMaybeUTF16(concatArgs), - prependArgs = prependArgs(concatArgs); + prependArgs = prependArgs(concatArgs, staticConcat); byte[] classBytes = ClassFile.of().build(CD_CONCAT, new Consumer() { - final boolean forceInline = concatArgs.parameterCount() < FORCE_INLINE_THRESHOLD; - @Override public void accept(ClassBuilder clb) { - clb.withSuperclass(CD_StringConcatBase) - .withFlags(ACC_FINAL | ACC_SUPER | ACC_SYNTHETIC) - .withMethodBody(INIT_NAME, MTD_INIT, 0, CONSTRUCTOR_BUILDER) - .withMethod("length", + if (staticConcat) { + clb.withSuperclass(CD_Object) + .withFlags(ACC_ABSTRACT | ACC_SUPER | ACC_SYNTHETIC); + } else { + clb.withSuperclass(CD_StringConcatBase) + .withFlags(ACC_FINAL | ACC_SUPER | ACC_SYNTHETIC) + .withMethodBody(INIT_NAME, MTD_INIT, 0, CONSTRUCTOR_BUILDER); + } + + clb.withMethod("length", lengthArgs, ACC_STATIC | ACC_PRIVATE, new Consumer() { @@ -1293,18 +1316,20 @@ public void accept(MethodBuilder mb) { if (forceInline) { mb.with(FORCE_INLINE); } - mb.withCode(generatePrependMethod(prependArgs)); + mb.withCode(generatePrependMethod(prependArgs, staticConcat, constants)); } }) .withMethod(METHOD_NAME, ConstantUtils.methodTypeDesc(concatArgs), - ACC_FINAL, + staticConcat ? ACC_STATIC | ACC_FINAL : ACC_FINAL, new Consumer() { public void accept(MethodBuilder mb) { if (forceInline) { mb.with(FORCE_INLINE); } mb.withCode(generateConcatMethod( + staticConcat, + constants, CD_CONCAT, concatArgs, lengthArgs, @@ -1330,11 +1355,16 @@ public void accept(MethodBuilder mb) { try { var hiddenClass = lookup.makeHiddenClassDefiner(CLASS_NAME, classBytes, Set.of(), DUMPER) .defineClass(true, null); + + if (staticConcat) { + return lookup.findStatic(hiddenClass, METHOD_NAME, concatArgs); + } + var constructor = lookup.findConstructor(hiddenClass, CONSTRUCTOR_METHOD_TYPE); - var concat = lookup.findVirtual(hiddenClass, METHOD_NAME, concatArgs); - CACHE.put(concatArgs, new SoftReference<>(new MethodHandlePair(constructor, concat))); - var instance = hiddenClass.cast(constructor.invoke(constants)); - return concat.bindTo(instance); + var concatenator = lookup.findVirtual(hiddenClass, METHOD_NAME, concatArgs); + CACHE.put(concatArgs, new SoftReference<>(new MethodHandlePair(constructor, concatenator))); + var instance = constructor.invokeBasic((Object)constants); + return concatenator.bindTo(instance); } catch (Throwable e) { throw new StringConcatException("Exception while spinning the class", e); } @@ -1405,6 +1435,8 @@ public void accept(MethodBuilder mb) { * */ private static Consumer generateConcatMethod( + boolean staticConcat, + String[] constants, ClassDesc concatClass, MethodType concatArgs, MethodTypeDesc lengthArgs, @@ -1416,7 +1448,7 @@ private static Consumer generateConcatMethod( public void accept(CodeBuilder cb) { // Compute parameter variable slots int paramCount = concatArgs.parameterCount(), - thisSlot = cb.receiverSlot(), + thisSlot = staticConcat ? 0 : cb.receiverSlot(), lengthSlot = cb.allocateLocal(TypeKind.INT), coderSlot = cb.allocateLocal(TypeKind.BYTE), bufSlot = cb.allocateLocal(TypeKind.REFERENCE), @@ -1452,11 +1484,30 @@ public void accept(CodeBuilder cb) { } } + int coder = JLA.stringInitCoder(), + length = 0; + if (staticConcat) { + for (var constant : constants) { + coder |= JLA.stringCoder(constant); + length += constant.length(); + } + } + /* * coder = coder(this.coder, arg0, arg1, ... argN); */ - cb.aload(thisSlot) - .getfield(concatClass, "coder", CD_byte); + if (staticConcat) { + // coder can only be 0 or 1 + if (coder == 0) { + cb.iconst_0(); + } else { + cb.iconst_1(); + } + } else { + cb.aload(thisSlot) + .getfield(concatClass, "coder", CD_byte); + } + if (coderArgs != null) { for (int i = 0; i < paramCount; i++) { var cl = concatArgs.parameterType(i); @@ -1475,8 +1526,13 @@ public void accept(CodeBuilder cb) { /* * length = length(this.length, arg0, arg1, ..., argN); */ - cb.aload(thisSlot) - .getfield(concatClass, "length", CD_int); + if (staticConcat) { + cb.ldc(length); + } else { + cb.aload(thisSlot) + .getfield(concatClass, "length", CD_int); + } + for (int i = 0; i < paramCount; i++) { var cl = concatArgs.parameterType(i); int paramSlot = cb.parameterSlot(i); @@ -1493,25 +1549,35 @@ public void accept(CodeBuilder cb) { * suffix = constants[paramCount]; * length -= suffix.length(); */ - cb.aload(thisSlot) - .getfield(concatClass, "constants", CD_Array_String) - .dup() - .astore(constantsSlot) - .ldc(paramCount) - .aaload() - .dup() - .astore(suffixSlot) - .invokevirtual(CD_String, "length", MTD_int) - .isub() - .istore(lengthSlot); + if (staticConcat) { + cb.ldc(constants[paramCount].length()) + .isub() + .istore(lengthSlot); + } else { + cb.aload(thisSlot) + .getfield(concatClass, "constants", CD_Array_String) + .dup() + .astore(constantsSlot) + .ldc(paramCount) + .aaload() + .dup() + .astore(suffixSlot) + .invokevirtual(CD_String, "length", MTD_int) + .isub() + .istore(lengthSlot); + } /* * Allocate buffer : * * buf = newArrayWithSuffix(suffix, length, coder) */ - cb.aload(suffixSlot) - .iload(lengthSlot) + if (staticConcat) { + cb.ldc(constants[paramCount]); + } else { + cb.aload(suffixSlot); + } + cb.iload(lengthSlot) .iload(coderSlot) .invokestatic(CD_StringConcatHelper, "newArrayWithSuffix", MTD_NEW_ARRAY_SUFFIX) .astore(bufSlot); @@ -1521,8 +1587,10 @@ public void accept(CodeBuilder cb) { */ cb.iload(lengthSlot) .iload(coderSlot) - .aload(bufSlot) - .aload(constantsSlot); + .aload(bufSlot); + if (!staticConcat) { + cb.aload(constantsSlot); + } for (int i = 0; i < paramCount; i++) { var cl = concatArgs.parameterType(i); int paramSlot = cb.parameterSlot(i); @@ -1646,7 +1714,10 @@ public void accept(CodeBuilder cb) { * } * */ - private static Consumer generatePrependMethod(MethodTypeDesc prependArgs) { + private static Consumer generatePrependMethod( + MethodTypeDesc prependArgs, + boolean staticConcat, String[] constants + ) { return new Consumer() { @Override public void accept(CodeBuilder cb) { @@ -1665,7 +1736,7 @@ public void accept(CodeBuilder cb) { * buf, arg1, constant[1]), buf, arg0, constant[0]); */ cb.iload(lengthSlot); - for (int i = prependArgs.parameterCount() - 1; i >= 4; i--) { + for (int i = prependArgs.parameterCount() - 1, end = staticConcat ? 3 : 4; i >= end; i--) { var cl = prependArgs.parameterType(i); var kind = TypeKind.from(cl); @@ -1686,11 +1757,17 @@ public void accept(CodeBuilder cb) { cb.iload(coderSlot) .aload(bufSlot) - .loadLocal(kind, cb.parameterSlot(i)) - .aload(constantsSlot) - .ldc(i - 4) - .aaload() - .invokestatic(CD_StringConcatHelper, "prepend", methodTypeDesc); + .loadLocal(kind, cb.parameterSlot(i)); + + if (staticConcat) { + cb.ldc(constants[i - 3]); + } else { + cb.aload(constantsSlot) + .ldc(i - 4) + .aaload(); + } + + cb.invokestatic(CD_StringConcatHelper, "prepend", methodTypeDesc); } cb.ireturn(); } diff --git a/src/java.base/share/classes/java/lang/reflect/AccessFlag.java b/src/java.base/share/classes/java/lang/reflect/AccessFlag.java index 92c6655552e..bc6b20be9a8 100644 --- a/src/java.base/share/classes/java/lang/reflect/AccessFlag.java +++ b/src/java.base/share/classes/java/lang/reflect/AccessFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -528,7 +528,7 @@ public enum Location { /** * Method location. - * @jvms 4.6 Method + * @jvms 4.6 Methods */ METHOD, @@ -540,31 +540,31 @@ public enum Location { /** * Method parameter location. - * @jvms 4.7.24. The MethodParameters Attribute + * @jvms 4.7.24 The MethodParameters Attribute */ METHOD_PARAMETER, /** * Module location - * @jvms 4.7.25. The Module Attribute + * @jvms 4.7.25 The Module Attribute */ MODULE, /** * Module requires location - * @jvms 4.7.25. The Module Attribute + * @jvms 4.7.25 The Module Attribute */ MODULE_REQUIRES, /** * Module exports location - * @jvms 4.7.25. The Module Attribute + * @jvms 4.7.25 The Module Attribute */ MODULE_EXPORTS, /** * Module opens location - * @jvms 4.7.25. The Module Attribute + * @jvms 4.7.25 The Module Attribute */ MODULE_OPENS; diff --git a/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java b/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java index 52580a4b821..cc1bcd7dfdd 100644 --- a/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java +++ b/src/java.base/share/classes/java/lang/reflect/AnnotatedElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -47,8 +47,8 @@ * * As defined by The Java Language Specification * section {@jls 9.7.4}, an annotation on an element is a - * declaration annotation and an annotation on a type is a - * type annotation. + * {@index "declaration annotation"} and an annotation on a type is a + * {@index "type annotation"}. * * Note that any annotations returned by methods on the {@link * AnnotatedType AnnotatedType} interface and its subinterfaces are @@ -78,21 +78,21 @@ * *
    * - *
  • An annotation A is directly present on an + *
  • An annotation A is {@index "directly present"} on an * element E if E has a {@code * RuntimeVisibleAnnotations} or {@code * RuntimeVisibleParameterAnnotations} or {@code * RuntimeVisibleTypeAnnotations} attribute, and the attribute * contains A. * - *
  • An annotation A is indirectly present on an + *
  • An annotation A is {@index "indirectly present"} on an * element E if E has a {@code RuntimeVisibleAnnotations} or * {@code RuntimeVisibleParameterAnnotations} or {@code RuntimeVisibleTypeAnnotations} * attribute, and A 's type is repeatable, and the attribute contains * exactly one annotation whose value element contains A and whose * type is the containing annotation type of A 's type. * - *
  • An annotation A is present on an element E if either: + *
  • An annotation A is {@index "present"} on an element E if either: * *
      * @@ -104,7 +104,7 @@ * *
    * - *
  • An annotation A is associated with an element E + *
  • An annotation A is {@index "associated"} with an element E * if either: * *
      diff --git a/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java b/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java index d5d00f34c86..47c6c410241 100644 --- a/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java +++ b/src/java.base/share/classes/java/lang/reflect/InvocationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -254,7 +254,7 @@ public Object invoke(Object proxy, Method method, Object[] args) * @throws Throwable anything thrown by the default method * @since 16 - * @jvms 5.4.3. Method Resolution + * @jvms 5.4.3 Resolution */ @CallerSensitive public static Object invokeDefault(Object proxy, Method method, Object... args) diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index 9b929509882..730b4b09757 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -755,7 +755,7 @@ void setMethodAccessor(MethodAccessor accessor) { * {@link Class} and no definition can be found for the * default class value. * @since 1.5 - * @jls 9.6.2 Defaults for Annotation Type Elements + * @jls 9.6.2 Defaults for Annotation Interface Elements */ public Object getDefaultValue() { if (annotationDefault == null) diff --git a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java index 6cfd7f9bb44..51ee21e46b3 100644 --- a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java +++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java @@ -31,8 +31,6 @@ import java.lang.invoke.MethodType; import java.lang.invoke.StringConcatFactory; import java.lang.invoke.TypeDescriptor; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -56,20 +54,14 @@ private ObjectMethods() { } private static final int MAX_STRING_CONCAT_SLOTS = 20; - private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class); - private static final MethodType NAMES_MT = MethodType.methodType(List.class); - private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false); + private static final MethodHandle FALSE = MethodHandles.zero(boolean.class); private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true); - private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0); + private static final MethodHandle ZERO = MethodHandles.zero(int.class); private static final MethodHandle CLASS_IS_INSTANCE; - private static final MethodHandle OBJECT_EQUALS; private static final MethodHandle OBJECTS_EQUALS; private static final MethodHandle OBJECTS_HASHCODE; private static final MethodHandle OBJECTS_TOSTRING; private static final MethodHandle OBJECT_EQ; - private static final MethodHandle OBJECT_HASHCODE; - private static final MethodHandle OBJECT_TO_STRING; - private static final MethodHandle STRING_FORMAT; private static final MethodHandle HASH_COMBINER; private static final HashMap, MethodHandle> primitiveEquals = new HashMap<>(); @@ -82,21 +74,8 @@ private ObjectMethods() { } MethodHandles.Lookup publicLookup = MethodHandles.publicLookup(); MethodHandles.Lookup lookup = MethodHandles.lookup(); - @SuppressWarnings("removal") - ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction() { - @Override public ClassLoader run() { return ClassLoader.getPlatformClassLoader(); } - }); - CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance", MethodType.methodType(boolean.class, Object.class)); - OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals", - MethodType.methodType(boolean.class, Object.class)); - OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode", - MethodType.fromMethodDescriptorString("()I", loader)); - OBJECT_TO_STRING = publicLookup.findVirtual(Object.class, "toString", - MethodType.methodType(String.class)); - STRING_FORMAT = publicLookup.findStatic(String.class, "format", - MethodType.methodType(String.class, String.class, Object[].class)); OBJECTS_EQUALS = publicLookup.findStatic(Objects.class, "equals", MethodType.methodType(boolean.class, Object.class, Object.class)); OBJECTS_HASHCODE = publicLookup.findStatic(Objects.class, "hashCode", @@ -107,41 +86,41 @@ private ObjectMethods() { } OBJECT_EQ = lookup.findStatic(OBJECT_METHODS_CLASS, "eq", MethodType.methodType(boolean.class, Object.class, Object.class)); HASH_COMBINER = lookup.findStatic(OBJECT_METHODS_CLASS, "hashCombiner", - MethodType.fromMethodDescriptorString("(II)I", loader)); + MethodType.methodType(int.class, int.class, int.class)); primitiveEquals.put(byte.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(BB)Z", loader))); + MethodType.methodType(boolean.class, byte.class, byte.class))); primitiveEquals.put(short.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(SS)Z", loader))); + MethodType.methodType(boolean.class, short.class, short.class))); primitiveEquals.put(char.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(CC)Z", loader))); + MethodType.methodType(boolean.class, char.class, char.class))); primitiveEquals.put(int.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(II)Z", loader))); + MethodType.methodType(boolean.class, int.class, int.class))); primitiveEquals.put(long.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(JJ)Z", loader))); + MethodType.methodType(boolean.class, long.class, long.class))); primitiveEquals.put(float.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(FF)Z", loader))); + MethodType.methodType(boolean.class, float.class, float.class))); primitiveEquals.put(double.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(DD)Z", loader))); + MethodType.methodType(boolean.class, double.class, double.class))); primitiveEquals.put(boolean.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq", - MethodType.fromMethodDescriptorString("(ZZ)Z", loader))); + MethodType.methodType(boolean.class, boolean.class, boolean.class))); primitiveHashers.put(byte.class, lookup.findStatic(Byte.class, "hashCode", - MethodType.fromMethodDescriptorString("(B)I", loader))); + MethodType.methodType(int.class, byte.class))); primitiveHashers.put(short.class, lookup.findStatic(Short.class, "hashCode", - MethodType.fromMethodDescriptorString("(S)I", loader))); + MethodType.methodType(int.class, short.class))); primitiveHashers.put(char.class, lookup.findStatic(Character.class, "hashCode", - MethodType.fromMethodDescriptorString("(C)I", loader))); + MethodType.methodType(int.class, char.class))); primitiveHashers.put(int.class, lookup.findStatic(Integer.class, "hashCode", - MethodType.fromMethodDescriptorString("(I)I", loader))); + MethodType.methodType(int.class, int.class))); primitiveHashers.put(long.class, lookup.findStatic(Long.class, "hashCode", - MethodType.fromMethodDescriptorString("(J)I", loader))); + MethodType.methodType(int.class, long.class))); primitiveHashers.put(float.class, lookup.findStatic(Float.class, "hashCode", - MethodType.fromMethodDescriptorString("(F)I", loader))); + MethodType.methodType(int.class, float.class))); primitiveHashers.put(double.class, lookup.findStatic(Double.class, "hashCode", - MethodType.fromMethodDescriptorString("(D)I", loader))); + MethodType.methodType(int.class, double.class))); primitiveHashers.put(boolean.class, lookup.findStatic(Boolean.class, "hashCode", - MethodType.fromMethodDescriptorString("(Z)I", loader))); + MethodType.methodType(int.class, boolean.class))); primitiveToString.put(byte.class, lookup.findStatic(Byte.class, "toString", MethodType.methodType(String.class, byte.class))); diff --git a/src/java.base/share/classes/java/net/NetworkInterface.java b/src/java.base/share/classes/java/net/NetworkInterface.java index f2d039d2502..90e52527b63 100644 --- a/src/java.base/share/classes/java/net/NetworkInterface.java +++ b/src/java.base/share/classes/java/net/NetworkInterface.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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,12 +35,43 @@ import java.util.stream.StreamSupport; /** - * This class represents a Network Interface made up of a name, - * and a list of IP addresses assigned to this interface. - * It is used to identify the local interface on which a multicast group - * is joined. + * This class represents a Network Interface. + *

      + * A Network Interface is an abstraction encapsulating + * the characteristics of a Network Interface Controller, or + * Virtual Network adapter, which is a system hardware/software + * component connecting a computer, or host system, to a computer + * network. A Network Interface can be physical or virtual. + * A Network Interface has a name, zero or more assigned + * {@linkplain InetAddress IP addresses}, zero or more {@linkplain + * InterfaceAddress MAC Addresses}, and may have an index. + * The name is highly platform specific but a name such as "le0" + * is typical; it may not be unique. The index is a highly platform + * specific number that identifies the interface. The network + * configuration may change during the lifetime of the JVM. + * For example, the set of IP addresses assigned to a network + * interface can be transient and dynamically allocated, and may + * change at any time. + *

      + * When obtaining a {@code NetworkInterface} instance, part of its + * configuration (such as its name and the list of assigned IP addresses), + * is reflective of its configuration at creation time. + * Obtaining an updated view of the network configuration may require + * looking up a network interface again in order to obtain a new instance. + *

      + * Network interface instances are typically used to identify the local + * interface on which a multicast group is joined. * - * Interfaces are normally known by names such as "le0". + * @apiNote Several static methods in this class are + * factory methods, returning a new instance of a {@code NetworkInterface}, + * reflecting the configuration at the time of instantiation. + * The network configuration may change at any time, and as such, + * these methods may need to be invoked again in order to obtain + * a more up-to-date view of the network interfaces. + * In particular, there is no guarantee that the same interface will be + * found at the same index, or that the same network addresses will be + * bound to the interface, if the network configuration of the system + * has changed. * * @since 1.4 */ @@ -87,7 +118,7 @@ public String getName() { } /** - * Get an Enumeration with all or a subset of the InetAddresses bound to + * Get an Enumeration with all, or a subset, of the InetAddresses bound to * this network interface. *

      * If there is a security manager, its {@code checkConnect} @@ -97,7 +128,12 @@ public String getName() { * {@link NetPermission}("getNetworkInformation") permission, then all * InetAddresses are returned. * - * @return an Enumeration object with all or a subset of the InetAddresses + * @implNote + * The returned enumeration contains all, or a subset, of the InetAddresses that were + * bound to the interface at the time the {@linkplain #getNetworkInterfaces() + * interface configuration was read} + * + * @return an Enumeration object with all, or a subset, of the InetAddresses * bound to this network interface * @see #inetAddresses() */ @@ -106,7 +142,7 @@ public Enumeration getInetAddresses() { } /** - * Get a Stream of all or a subset of the InetAddresses bound to this + * Get a Stream of all, or a subset, of the InetAddresses bound to this * network interface. *

      * If there is a security manager, its {@code checkConnect} @@ -116,7 +152,12 @@ public Enumeration getInetAddresses() { * {@link NetPermission}("getNetworkInformation") permission, then all * InetAddresses are returned. * - * @return a Stream object with all or a subset of the InetAddresses + * @implNote + * The stream contains all, or a subset, of the InetAddresses that were + * bound to the interface at the time the {@linkplain #getNetworkInterfaces() + * interface configuration was read} + * + * @return a Stream object with all, or a subset, of the InetAddresses * bound to this network interface * @since 9 */ @@ -150,7 +191,7 @@ private InetAddress[] getCheckedInetAddresses() { } /** - * Get a List of all or a subset of the {@code InterfaceAddresses} + * Get a List of all, or a subset, of the {@code InterfaceAddresses} * of this network interface. *

      * If there is a security manager, its {@code checkConnect} @@ -158,7 +199,7 @@ private InetAddress[] getCheckedInetAddresses() { * Only InterfaceAddresses where the {@code checkConnect} doesn't throw * a SecurityException will be returned in the List. * - * @return a {@code List} object with all or a subset of the + * @return a {@code List} object with all, or a subset, of the * InterfaceAddress of this network interface * @since 1.6 */ @@ -249,6 +290,12 @@ public String getDisplayName() { /** * Searches for the network interface with the specified name. * + * @apiNote + * The returned interface instance may reflect a snapshot of the + * configuration taken at the time the instance is created. + * See the general discussion of {@linkplain NetworkInterface##lookup + * snapshots and configuration} for the semantics of the returned interface. + * * @param name * The name of the network interface. * @@ -271,6 +318,12 @@ public static NetworkInterface getByName(String name) throws SocketException { /** * Get a network interface given its index. * + * @apiNote + * The returned interface instance may reflect a snapshot of the + * configuration taken at the time the instance is created. + * See the general discussion of {@linkplain NetworkInterface##lookup + * snapshots and configuration} for the semantics of the returned interface. + * * @param index an integer, the index of the interface * @return the NetworkInterface obtained from its index, or {@code null} if * there is no interface with such an index on the system @@ -294,6 +347,12 @@ public static NetworkInterface getByIndex(int index) throws SocketException { * interfaces it is not defined which network interface is * returned. * + * @apiNote + * The returned interface instance may reflect a snapshot of the + * configuration taken at the time the instance is created. + * See the general discussion of {@linkplain NetworkInterface##lookup + * snapshots and configuration} for the semantics of the returned interface. + * * @param addr * The {@code InetAddress} to search with. * @@ -334,8 +393,14 @@ public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketE * a loopback interface that only supports communication between entities on * this machine. * - * @apiNote this method can be used in combination with - * {@link #getInetAddresses()} to obtain all IP addresses for this node + * @apiNote + * This method can be used in combination with + * {@link #getInetAddresses()} to obtain all IP addresses for this node. + *

      + * The returned interface instances may reflect a snapshot of the + * configuration taken at the time the instance is created. + * See the general discussion of {@linkplain NetworkInterface##lookup + * snapshots and configuration} for the semantics of the returned interface. * * @return an Enumeration of NetworkInterfaces found on this machine * @throws SocketException if an I/O error occurs, @@ -359,13 +424,18 @@ public static Enumeration getNetworkInterfaces() * loopback interface that only supports communication between entities on * this machine. * - * @apiNote this method can be used in combination with + * @apiNote This method can be used in combination with * {@link #inetAddresses()}} to obtain a stream of all IP addresses for * this node, for example: *

       {@code
            * Stream addrs = NetworkInterface.networkInterfaces()
            *     .flatMap(NetworkInterface::inetAddresses);
            * }
      + *

      + * The returned interface instances may reflect a snapshot of the + * configuration taken at the time the instance is created. + * See the general discussion of {@linkplain NetworkInterface##lookup + * snapshots and configuration} for the semantics of the returned interface. * * @return a Stream of NetworkInterfaces found on this machine * @throws SocketException if an I/O error occurs, diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index 7bfcbea9639..828ae417f79 100644 --- a/src/java.base/share/classes/java/nio/Buffer.java +++ b/src/java.base/share/classes/java/nio/Buffer.java @@ -27,6 +27,7 @@ import jdk.internal.access.JavaNioAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.access.foreign.MappedMemoryUtilsProxy; import jdk.internal.access.foreign.UnmapperProxy; import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.MemorySessionImpl; @@ -804,6 +805,7 @@ final void checkSession() { } static { + // setup access to this package in SharedSecrets SharedSecrets.setJavaNioAccess( new JavaNioAccess() { @@ -886,23 +888,8 @@ public boolean hasSession(Buffer buffer) { } @Override - public void force(FileDescriptor fd, long address, boolean isSync, long offset, long size) { - MappedMemoryUtils.force(fd, address, isSync, offset, size); - } - - @Override - public void load(long address, boolean isSync, long size) { - MappedMemoryUtils.load(address, isSync, size); - } - - @Override - public void unload(long address, boolean isSync, long size) { - MappedMemoryUtils.unload(address, isSync, size); - } - - @Override - public boolean isLoaded(long address, boolean isSync, long size) { - return MappedMemoryUtils.isLoaded(address, isSync, size); + public MappedMemoryUtilsProxy mappedMemoryUtils() { + return MappedMemoryUtils.PROXY; } @Override diff --git a/src/java.base/share/classes/java/nio/MappedByteBuffer.java b/src/java.base/share/classes/java/nio/MappedByteBuffer.java index d560d3843d2..9c1f21c7370 100644 --- a/src/java.base/share/classes/java/nio/MappedByteBuffer.java +++ b/src/java.base/share/classes/java/nio/MappedByteBuffer.java @@ -31,6 +31,7 @@ import java.lang.ref.Reference; import java.util.Objects; +import jdk.internal.access.foreign.MappedMemoryUtilsProxy; import jdk.internal.access.foreign.UnmapperProxy; import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.misc.Unsafe; @@ -194,7 +195,7 @@ public final boolean isLoaded() { if (fd == null) { return true; } - return SCOPED_MEMORY_ACCESS.isLoaded(session(), address, isSync, capacity()); + return SCOPED_MEMORY_ACCESS.isLoaded(session(), MappedMemoryUtils.PROXY, address, isSync, capacity()); } /** @@ -212,7 +213,7 @@ public final MappedByteBuffer load() { return this; } try { - SCOPED_MEMORY_ACCESS.load(session(), address, isSync, capacity()); + SCOPED_MEMORY_ACCESS.load(session(), MappedMemoryUtils.PROXY, address, isSync, capacity()); } finally { Reference.reachabilityFence(this); } @@ -312,7 +313,7 @@ public final MappedByteBuffer force(int index, int length) { if ((address != 0) && (capacity != 0)) { // check inputs Objects.checkFromIndexSize(index, length, capacity); - SCOPED_MEMORY_ACCESS.force(session(), fd, address, isSync, index, length); + SCOPED_MEMORY_ACCESS.force(session(), MappedMemoryUtils.PROXY, fd, address, isSync, index, length); } return this; } diff --git a/src/java.base/share/classes/java/nio/MappedMemoryUtils.java b/src/java.base/share/classes/java/nio/MappedMemoryUtils.java index cf6f953d8b2..d0ec627f817 100644 --- a/src/java.base/share/classes/java/nio/MappedMemoryUtils.java +++ b/src/java.base/share/classes/java/nio/MappedMemoryUtils.java @@ -28,6 +28,8 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.UncheckedIOException; + +import jdk.internal.access.foreign.MappedMemoryUtilsProxy; import jdk.internal.misc.Blocker; import jdk.internal.misc.Unsafe; @@ -116,6 +118,17 @@ static void force(FileDescriptor fd, long address, boolean isSync, long index, l private static native void unload0(long address, long length); private static native void force0(FileDescriptor fd, long address, long length) throws IOException; + /* Register the natives via the static initializer. + * + * This is required, as these native methods are "scoped methods" (see ScopedMemoryAccess). + * As such, it's better not to end up doing a full JNI lookup while in a scoped method context, + * as that will make the stack trace too deep. + */ + private static native void registerNatives(); + static { + registerNatives(); + } + // utility methods // Returns the distance (in bytes) of the buffer start from the @@ -164,4 +177,26 @@ private static long alignDown(long address, int pageSize) { // pageSize must be a power of 2 return address & ~(pageSize - 1); } + + static final MappedMemoryUtilsProxy PROXY = new MappedMemoryUtilsProxy() { + @Override + public boolean isLoaded(long address, boolean isSync, long size) { + return MappedMemoryUtils.isLoaded(address, isSync, size); + } + + @Override + public void load(long address, boolean isSync, long size) { + MappedMemoryUtils.load(address, isSync, size); + } + + @Override + public void unload(long address, boolean isSync, long size) { + MappedMemoryUtils.unload(address, isSync, size); + } + + @Override + public void force(FileDescriptor fd, long address, boolean isSync, long index, long length) { + MappedMemoryUtils.force(fd, address, isSync, index, length); + } + }; } diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java index 4242b5da04a..fac7f6b9383 100644 --- a/src/java.base/share/classes/java/security/SecureRandom.java +++ b/src/java.base/share/classes/java/security/SecureRandom.java @@ -225,8 +225,8 @@ private boolean getThreadSafe() { if (provider == null || algorithm == null) { return false; } else { - return Boolean.parseBoolean(provider.getProperty( - "SecureRandom." + algorithm + " ThreadSafe", "false")); + Service service = provider.getService("SecureRandom", algorithm); + return Boolean.parseBoolean(service.getAttribute("ThreadSafe")); } } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 51d4ef51c1f..0436cbb314f 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -29,6 +29,7 @@ import java.io.PrintStream; import java.lang.annotation.Annotation; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.lang.module.ModuleDescriptor; @@ -43,9 +44,11 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.stream.Stream; +import jdk.internal.loader.NativeLibraries; import jdk.internal.misc.CarrierThreadLocal; import jdk.internal.module.ServicesCatalog; import jdk.internal.reflect.ConstantPool; @@ -318,6 +321,11 @@ public interface JavaLangAccess { */ int countPositives(byte[] ba, int off, int len); + /** + * Count the number of leading non-zero ascii chars in the String. + */ + int countNonZeroAscii(String s); + /** * Constructs a new {@code String} by decoding the specified subarray of * bytes using the specified {@linkplain java.nio.charset.Charset charset}. @@ -452,6 +460,16 @@ public interface JavaLangAccess { Object stringConcat1(String[] constants); + /** + * Get the string initial coder, When COMPACT_STRINGS is on, it returns 0, and when it is off, it returns 1. + */ + byte stringInitCoder(); + + /** + * Get the Coder of String, which is used by StringConcatFactory to calculate the initCoder of constants + */ + byte stringCoder(String str); + /** * Join strings */ @@ -473,7 +491,11 @@ public interface JavaLangAccess { int getCharsUTF16(long i, int index, byte[] buf); - long findNative(ClassLoader loader, String entry); + /** + * Returns the {@link NativeLibraries} object associated with the provided class loader. + * This is used by {@link SymbolLookup#loaderLookup()}. + */ + NativeLibraries nativeLibrariesFor(ClassLoader loader); /** * Direct access to Shutdown.exit to avoid security manager checks @@ -585,6 +607,11 @@ public interface JavaLangAccess { */ void unparkVirtualThread(Thread thread); + /** + * Returns the virtual thread default scheduler. + */ + Executor virtualThreadDefaultScheduler(); + /** * Creates a new StackWalker */ diff --git a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java index b34a0d42085..a5d7c843998 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java @@ -25,6 +25,7 @@ package jdk.internal.access; +import jdk.internal.access.foreign.MappedMemoryUtilsProxy; import jdk.internal.access.foreign.UnmapperProxy; import jdk.internal.misc.VM.BufferPool; @@ -107,25 +108,10 @@ public interface JavaNioAccess { boolean hasSession(Buffer buffer); - /** - * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views. - */ - void force(FileDescriptor fd, long address, boolean isSync, long offset, long size); - - /** - * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views. - */ - void load(long address, boolean isSync, long size); - /** * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl}. */ - void unload(long address, boolean isSync, long size); - - /** - * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views. - */ - boolean isLoaded(long address, boolean isSync, long size); + MappedMemoryUtilsProxy mappedMemoryUtils(); /** * Used by {@code jdk.internal.foreign.NativeMemorySegmentImpl}. diff --git a/src/java.base/share/classes/sun/security/provider/SHAKE256.java b/src/java.base/share/classes/jdk/internal/access/foreign/MappedMemoryUtilsProxy.java similarity index 62% rename from src/java.base/share/classes/sun/security/provider/SHAKE256.java rename to src/java.base/share/classes/jdk/internal/access/foreign/MappedMemoryUtilsProxy.java index 5dab92fdd78..eb5cf388470 100644 --- a/src/java.base/share/classes/sun/security/provider/SHAKE256.java +++ b/src/java.base/share/classes/jdk/internal/access/foreign/MappedMemoryUtilsProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,28 +22,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package sun.security.provider; -/* - * The SHAKE256 extendable output function. - */ -public final class SHAKE256 extends SHA3 { - public SHAKE256(int d) { - super("SHAKE256", d, (byte) 0x1F, 64); - } +package jdk.internal.access.foreign; - public void update(byte in) { - engineUpdate(in); - } - public void update(byte[] in, int off, int len) { - engineUpdate(in, off, len); - } +import java.io.FileDescriptor; - public byte[] digest() { - return engineDigest(); - } - - public void reset() { - engineReset(); - } +/** + * This proxy interface is required to allow access to @{code MappedMemoryUtils} methods from {@code ScopedMemoryAccess}. + * This allows to avoid pesky initialization issues in the middle of memory mapped scoped methods. + */ +public interface MappedMemoryUtilsProxy { + boolean isLoaded(long address, boolean isSync, long size); + void load(long address, boolean isSync, long size); + void unload(long address, boolean isSync, long size); + void force(FileDescriptor fd, long address, boolean isSync, long index, long length); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 8be167cd119..50c0bdc2a9f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java @@ -62,13 +62,13 @@ public final String name() { } @Override - public final void writeAttribute(BufWriter buf, T attr) { + public final void writeAttribute(BufWriter writer, T attr) { + BufWriterImpl buf = (BufWriterImpl) writer; buf.writeIndex(buf.constantPool().utf8Entry(name)); - buf.writeInt(0); - int start = buf.size(); + int lengthIndex = buf.skip(4); writeBody(buf, attr); - int written = buf.size() - start; - buf.patchInt(start - 4, 4, written); + int written = buf.size() - lengthIndex - 4; + buf.patchInt(lengthIndex, written); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java index f574627491f..6b75a44a6bf 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java @@ -51,7 +51,7 @@ public void setOriginal(M original) { } public void writeAttribute(Attribute a) { - if (Util.isAttributeAllowed(a, context.attributesProcessingOption())) { + if (Util.isAttributeAllowed(a, context)) { attributes.withAttribute(a); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 10c9cf0a5e1..48c0cb76857 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -94,7 +94,6 @@ public abstract sealed class AbstractInstruction FMT_Discontinued = "Discontinued[OP=%s]"; final Opcode op; - final int size; @Override public Opcode opcode() { @@ -103,12 +102,12 @@ public Opcode opcode() { @Override public int sizeInBytes() { - return size; + // Note: only lookupswitch and tableswitch have variable sizes + return op.sizeIfFixed(); } - public AbstractInstruction(Opcode op, int size) { + AbstractInstruction(Opcode op) { this.op = op; - this.size = size; } @Override @@ -118,8 +117,8 @@ public abstract static sealed class BoundInstruction extends AbstractInstruction final CodeImpl code; final int pos; - protected BoundInstruction(Opcode op, int size, CodeImpl code, int pos) { - super(op, size); + protected BoundInstruction(Opcode op, CodeImpl code, int pos) { + super(op); this.code = code; this.pos = pos; } @@ -131,7 +130,7 @@ protected Label offsetToLabel(int offset) { @Override public void writeTo(DirectCodeBuilder writer) { // Override this if the instruction has any CP references or labels! - code.classReader.copyBytesTo(writer.bytecodesBufWriter, pos, size); + code.classReader.copyBytesTo(writer.bytecodesBufWriter, pos, op.sizeIfFixed()); } } @@ -139,7 +138,7 @@ public static final class BoundLoadInstruction extends BoundInstruction implements LoadInstruction { public BoundLoadInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @@ -155,7 +154,7 @@ public String toString() { @Override public int slot() { - return switch (size) { + return switch (sizeInBytes()) { case 2 -> code.classReader.readU1(pos + 1); case 4 -> code.classReader.readU2(pos + 2); default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op); @@ -168,7 +167,7 @@ public static final class BoundStoreInstruction extends BoundInstruction implements StoreInstruction { public BoundStoreInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -183,10 +182,10 @@ public String toString() { @Override public int slot() { - return switch (size) { + return switch (sizeInBytes()) { case 2 -> code.classReader.readU1(pos + 1); case 4 -> code.classReader.readU2(pos + 2); - default -> throw new IllegalArgumentException("Unexpected op size: " + size + " -- " + op); + default -> throw new IllegalArgumentException("Unexpected op size: " + sizeInBytes() + " -- " + op); }; } @@ -196,17 +195,17 @@ public static final class BoundIncrementInstruction extends BoundInstruction implements IncrementInstruction { public BoundIncrementInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override public int slot() { - return size == 6 ? code.classReader.readU2(pos + 2) : code.classReader.readU1(pos + 1); + return sizeInBytes() == 6 ? code.classReader.readU2(pos + 2) : code.classReader.readU1(pos + 1); } @Override public int constant() { - return size == 6 ? code.classReader.readS2(pos + 4) : (byte) code.classReader.readS1(pos + 2); + return sizeInBytes() == 6 ? code.classReader.readS2(pos + 4) : code.classReader.readS1(pos + 2); } @Override @@ -220,7 +219,7 @@ public static final class BoundBranchInstruction extends BoundInstruction implements BranchInstruction { public BoundBranchInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -229,8 +228,8 @@ public Label target() { } public int branchByteOffset() { - return size == 3 - ? (int) (short) code.classReader.readU2(pos + 1) + return sizeInBytes() == 3 + ? code.classReader.readS2(pos + 1) : code.classReader.readInt(pos + 1); } @@ -256,33 +255,31 @@ public static final class BoundLookupSwitchInstruction // will always need size, cache everything to there private final int afterPad; private final int npairs; + private final int size; BoundLookupSwitchInstruction(Opcode op, CodeImpl code, int pos) { - super(op, size(code, code.codeStart, pos), code, pos); - - this.afterPad = pos + 1 + ((4 - ((pos + 1 - code.codeStart) & 3)) & 3); + super(op, code, pos); + this.afterPad = code.codeStart + RawBytecodeHelper.align(pos + 1 - code.codeStart); this.npairs = code.classReader.readInt(afterPad + 4); if (npairs < 0 || npairs > code.codeLength >> 3) { throw new IllegalArgumentException("Invalid lookupswitch npairs value: " + npairs); } - } - - static int size(CodeImpl code, int codeStart, int pos) { - int afterPad = pos + 1 + ((4 - ((pos + 1 - codeStart) & 3)) & 3); - int pad = afterPad - (pos + 1); - int npairs = code.classReader.readInt(afterPad + 4); - return 1 + pad + 8 + npairs * 8; + this.size = afterPad + 8 + npairs * 8 - pos; } private int defaultOffset() { return code.classReader.readInt(afterPad); } + @Override + public int sizeInBytes() { + return size; + } + @Override public List cases() { var cases = new SwitchCase[npairs]; - for (int i = 0; i < npairs; ++i) { - int z = afterPad + 8 + 8 * i; + for (int i = 0, z = afterPad + 8; i < npairs; ++i, z += 8) { cases[i] = SwitchCase.of(code.classReader.readInt(z), offsetToLabel(code.classReader.readInt(z + 4))); } return List.of(cases); @@ -308,25 +305,26 @@ public String toString() { public static final class BoundTableSwitchInstruction extends BoundInstruction implements TableSwitchInstruction { - BoundTableSwitchInstruction(Opcode op, CodeImpl code, int pos) { - super(op, size(code, code.codeStart, pos), code, pos); - } + private final int afterPad; + private final int low; + private final int high; + private final int size; - static int size(CodeImpl code, int codeStart, int pos) { - int ap = pos + 1 + ((4 - ((pos + 1 - codeStart) & 3)) & 3); - int pad = ap - (pos + 1); - int low = code.classReader.readInt(ap + 4); - int high = code.classReader.readInt(ap + 8); + BoundTableSwitchInstruction(Opcode op, CodeImpl code, int pos) { + super(op, code, pos); + afterPad = code.codeStart + RawBytecodeHelper.align(pos + 1 - code.codeStart); + low = code.classReader.readInt(afterPad + 4); + high = code.classReader.readInt(afterPad + 8); if (high < low || (long)high - low > code.codeLength >> 2) { throw new IllegalArgumentException("Invalid tableswitch values low: " + low + " high: " + high); } int cnt = high - low + 1; - return 1 + pad + 12 + cnt * 4; + size = afterPad + 12 + cnt * 4 - pos; } - private int afterPadding() { - int p = pos; - return p + 1 + ((4 - ((p + 1 - code.codeStart) & 3)) & 3); + @Override + public int sizeInBytes() { + return size; } @Override @@ -336,12 +334,12 @@ public Label defaultTarget() { @Override public int lowValue() { - return code.classReader.readInt(afterPadding() + 4); + return low; } @Override public int highValue() { - return code.classReader.readInt(afterPadding() + 8); + return high; } @Override @@ -350,19 +348,17 @@ public List cases() { int high = highValue(); int defOff = defaultOffset(); var cases = new ArrayList(high - low + 1); - int z = afterPadding() + 12; - for (int i = lowValue(); i <= high; ++i) { + for (int i = low, z = afterPad + 12; i <= high; ++i, z += 4) { int off = code.classReader.readInt(z); if (defOff != off) { cases.add(SwitchCase.of(i, offsetToLabel(off))); } - z += 4; } return Collections.unmodifiableList(cases); } private int defaultOffset() { - return code.classReader.readInt(afterPadding()); + return code.classReader.readInt(afterPad); } @Override @@ -383,7 +379,7 @@ public static final class BoundFieldInstruction private FieldRefEntry fieldEntry; public BoundFieldInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -413,7 +409,7 @@ public static final class BoundInvokeInstruction MemberRefEntry methodEntry; public BoundInvokeInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -453,7 +449,7 @@ public static final class BoundInvokeInterfaceInstruction InterfaceMethodRefEntry methodEntry; public BoundInvokeInterfaceInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -493,7 +489,7 @@ public static final class BoundInvokeDynamicInstruction InvokeDynamicEntry indyEntry; BoundInvokeDynamicInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -523,7 +519,7 @@ public static final class BoundNewObjectInstruction ClassEntry classEntry; BoundNewObjectInstruction(CodeImpl code, int pos) { - super(Opcode.NEW, Opcode.NEW.sizeIfFixed(), code, pos); + super(Opcode.NEW, code, pos); } @Override @@ -552,7 +548,7 @@ public static final class BoundNewPrimitiveArrayInstruction extends BoundInstruction implements NewPrimitiveArrayInstruction { public BoundNewPrimitiveArrayInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -571,7 +567,7 @@ public static final class BoundNewReferenceArrayInstruction extends BoundInstruction implements NewReferenceArrayInstruction { public BoundNewReferenceArrayInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -597,7 +593,7 @@ public static final class BoundNewMultidimensionalArrayInstruction extends BoundInstruction implements NewMultiArrayInstruction { public BoundNewMultidimensionalArrayInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -630,7 +626,7 @@ public static final class BoundTypeCheckInstruction ClassEntry typeEntry; public BoundTypeCheckInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -659,7 +655,7 @@ public static final class BoundArgumentConstantInstruction extends BoundInstruction implements ConstantInstruction.ArgumentConstantInstruction { public BoundArgumentConstantInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -668,7 +664,7 @@ public Integer constantValue() { } public int constantInt() { - return size == 3 ? code.classReader.readS2(pos + 1) : code.classReader.readS1(pos + 1); + return sizeInBytes() == 3 ? code.classReader.readS2(pos + 1) : code.classReader.readS1(pos + 1); } @Override @@ -682,7 +678,7 @@ public static final class BoundLoadConstantInstruction extends BoundInstruction implements ConstantInstruction.LoadConstantInstruction { public BoundLoadConstantInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -717,7 +713,7 @@ public static final class BoundJsrInstruction extends BoundInstruction implements DiscontinuedInstruction.JsrInstruction { public BoundJsrInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -726,7 +722,7 @@ public Label target() { } public int branchByteOffset() { - return size == 3 + return sizeInBytes() == 3 ? code.classReader.readS2(pos + 1) : code.classReader.readInt(pos + 1); } @@ -747,7 +743,7 @@ public static final class BoundRetInstruction extends BoundInstruction implements DiscontinuedInstruction.RetInstruction { public BoundRetInstruction(Opcode op, CodeImpl code, int pos) { - super(op, op.sizeIfFixed(), code, pos); + super(op, code, pos); } @Override @@ -757,7 +753,7 @@ public String toString() { @Override public int slot() { - return switch (size) { + return switch (sizeInBytes()) { case 2 -> code.classReader.readU1(pos + 1); case 4 -> code.classReader.readU2(pos + 2); default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op); @@ -769,7 +765,7 @@ public int slot() { public abstract static sealed class UnboundInstruction extends AbstractInstruction { UnboundInstruction(Opcode op) { - super(op, op.sizeIfFixed()); + super(op); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index bc885291b44..450f6ae1c8c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -409,60 +409,14 @@ public boolean equalsString(String s) { @Override void writeTo(BufWriterImpl pool) { + pool.writeU1(tag); if (rawBytes != null) { - pool.writeU1(tag); pool.writeU2(rawLen); pool.writeBytes(rawBytes, offset, rawLen); } else { // state == STRING and no raw bytes - if (stringValue.length() > 65535) { - throw new IllegalArgumentException("string too long"); - } - pool.writeU1(tag); - pool.writeU2(charLen); - for (int i = 0; i < charLen; ++i) { - char c = stringValue.charAt(i); - if (c >= '\001' && c <= '\177') { - // Optimistic writing -- hope everything is bytes - // If not, we bail out, and alternate path patches the length - pool.writeU1((byte) c); - } - else { - int charLength = stringValue.length(); - int byteLength = i; - char c1; - for (int j = i; j < charLength; ++j) { - c1 = (stringValue).charAt(j); - if (c1 >= '\001' && c1 <= '\177') { - byteLength++; - } else if (c1 > '\u07FF') { - byteLength += 3; - } else { - byteLength += 2; - } - } - if (byteLength > 65535) { - throw new IllegalArgumentException(); - } - int byteLengthFinal = byteLength; - pool.patchInt(pool.size() - i - 2, 2, byteLengthFinal); - for (int j = i; j < charLength; ++j) { - c1 = (stringValue).charAt(j); - if (c1 >= '\001' && c1 <= '\177') { - pool.writeU1((byte) c1); - } else if (c1 > '\u07FF') { - pool.writeU1((byte) (0xE0 | c1 >> 12 & 0xF)); - pool.writeU1((byte) (0x80 | c1 >> 6 & 0x3F)); - pool.writeU1((byte) (0x80 | c1 & 0x3F)); - } else { - pool.writeU1((byte) (0xC0 | c1 >> 6 & 0x1F)); - pool.writeU1((byte) (0x80 | c1 & 0x3F)); - } - } - break; - } - } + pool.writeUTF(stringValue); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 255e5e21cf0..15d3c8f5b34 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +26,6 @@ package jdk.internal.classfile.impl; -import java.nio.ByteBuffer; import java.util.Arrays; import java.lang.classfile.BufWriter; @@ -34,7 +34,11 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.PoolEntry; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + public final class BufWriterImpl implements BufWriter { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private final ConstantPoolBuilder constantPool; private final ClassFileImpl context; @@ -152,6 +156,52 @@ public void writeBytes(BufWriterImpl other) { writeBytes(other.elems, 0, other.offset); } + @SuppressWarnings("deprecation") + void writeUTF(String str) { + int strlen = str.length(); + int countNonZeroAscii = JLA.countNonZeroAscii(str); + int utflen = strlen; + if (countNonZeroAscii != strlen) { + for (int i = countNonZeroAscii; i < strlen; i++) { + int c = str.charAt(i); + if (c >= 0x80 || c == 0) + utflen += (c >= 0x800) ? 2 : 1; + } + } + if (utflen > 65535) { + throw new IllegalArgumentException("string too long"); + } + reserveSpace(utflen + 2); + + int offset = this.offset; + byte[] elems = this.elems; + + elems[offset ] = (byte) (utflen >> 8); + elems[offset + 1] = (byte) utflen; + offset += 2; + + str.getBytes(0, countNonZeroAscii, elems, offset); + offset += countNonZeroAscii; + + for (int i = countNonZeroAscii; i < strlen; ++i) { + char c = str.charAt(i); + if (c >= '\001' && c <= '\177') { + elems[offset++] = (byte) c; + } else if (c > '\u07FF') { + elems[offset ] = (byte) (0xE0 | c >> 12 & 0xF); + elems[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F); + elems[offset + 2] = (byte) (0x80 | c & 0x3F); + offset += 3; + } else { + elems[offset ] = (byte) (0xC0 | c >> 6 & 0x1F); + elems[offset + 1] = (byte) (0x80 | c & 0x3F); + offset += 2; + } + } + + this.offset = offset; + } + @Override public void writeBytes(byte[] arr, int start, int length) { reserveSpace(length); @@ -167,6 +217,20 @@ public void patchInt(int offset, int size, int value) { this.offset = prevOffset; } + public void patchU2(int offset, int x) { + byte[] elems = this.elems; + elems[offset ] = (byte) (x >> 8); + elems[offset + 1] = (byte) x; + } + + public void patchInt(int offset, int x) { + byte[] elems = this.elems; + elems[offset ] = (byte) (x >> 24); + elems[offset + 1] = (byte) (x >> 16); + elems[offset + 2] = (byte) (x >> 8); + elems[offset + 3] = (byte) x; + } + @Override public void writeIntBytes(int intSize, long intValue) { reserveSpace(intSize); @@ -175,6 +239,18 @@ public void writeIntBytes(int intSize, long intValue) { } } + /** + * Skip a few bytes in the output buffer. The skipped area has undefined value. + * @param bytes number of bytes to skip + * @return the index, for later patching + */ + public int skip(int bytes) { + int now = offset; + reserveSpace(bytes); + offset += bytes; + return now; + } + @Override public void reserveSpace(int freeBytes) { int minCapacity = offset + freeBytes; @@ -196,8 +272,8 @@ public int size() { return offset; } - public ByteBuffer asByteBuffer() { - return ByteBuffer.wrap(elems, 0, offset).slice(); + public RawBytecodeHelper.CodeRange bytecodeView() { + return RawBytecodeHelper.of(elems, offset); } public void copyTo(byte[] array, int bufferOffset) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java index 1fd4c5cb1a0..c6d9e55d8db 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java @@ -31,7 +31,6 @@ import java.lang.classfile.AttributeMapper; import java.lang.classfile.ClassFile; -import java.lang.classfile.ClassFile.*; import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassHierarchyResolver; import java.lang.classfile.ClassModel; @@ -41,33 +40,53 @@ import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.verifier.VerifierImpl; -public record ClassFileImpl(StackMapsOption stackMapsOption, - DebugElementsOption debugElementsOption, - LineNumbersOption lineNumbersOption, - AttributesProcessingOption attributesProcessingOption, - ConstantPoolSharingOption constantPoolSharingOption, - ShortJumpsOption shortJumpsOption, - DeadCodeOption deadCodeOption, - DeadLabelsOption deadLabelsOption, - ClassHierarchyResolverOption classHierarchyResolverOption, - AttributeMapperOption attributeMapperOption) implements ClassFile { +public final class ClassFileImpl implements ClassFile { + + private Option stackMapsOption; + private Option debugElementsOption; + private Option lineNumbersOption; + private Option attributesProcessingOption; + private Option constantPoolSharingOption; + private Option shortJumpsOption; + private Option deadCodeOption; + private Option deadLabelsOption; + private Option classHierarchyResolverOption; + private Option attributeMapperOption; + + private ClassFileImpl(Option stackMapsOption, + Option debugElementsOption, + Option lineNumbersOption, + Option attributesProcessingOption, + Option constantPoolSharingOption, + Option shortJumpsOption, + Option deadCodeOption, + Option deadLabelsOption, + Option classHierarchyResolverOption, + Option attributeMapperOption) { + this.stackMapsOption = stackMapsOption; + this.debugElementsOption = debugElementsOption; + this.lineNumbersOption = lineNumbersOption; + this.attributesProcessingOption = attributesProcessingOption; + this.constantPoolSharingOption = constantPoolSharingOption; + this.shortJumpsOption = shortJumpsOption; + this.deadCodeOption = deadCodeOption; + this.deadLabelsOption = deadLabelsOption; + this.classHierarchyResolverOption = classHierarchyResolverOption; + this.attributeMapperOption = attributeMapperOption; + } public static final ClassFileImpl DEFAULT_CONTEXT = new ClassFileImpl( - StackMapsOption.STACK_MAPS_WHEN_REQUIRED, - DebugElementsOption.PASS_DEBUG, - LineNumbersOption.PASS_LINE_NUMBERS, - AttributesProcessingOption.PASS_ALL_ATTRIBUTES, - ConstantPoolSharingOption.SHARED_POOL, - ShortJumpsOption.FIX_SHORT_JUMPS, - DeadCodeOption.PATCH_DEAD_CODE, - DeadLabelsOption.FAIL_ON_DEAD_LABELS, - new ClassHierarchyResolverOptionImpl(ClassHierarchyResolver.defaultResolver()), - new AttributeMapperOptionImpl(new Function<>() { - @Override - public AttributeMapper apply(Utf8Entry k) { - return null; - } - })); + null, // StackMapsOption.STACK_MAPS_WHEN_REQUIRED + null, // DebugElementsOption.PASS_DEBUG, + null, // LineNumbersOption.PASS_LINE_NUMBERS, + null, // AttributesProcessingOption.PASS_ALL_ATTRIBUTES, + null, // ConstantPoolSharingOption.SHARED_POOL, + null, // ShortJumpsOption.FIX_SHORT_JUMPS, + null, // DeadCodeOption.PATCH_DEAD_CODE, + null, // DeadLabelsOption.FAIL_ON_DEAD_LABELS, + null, // new ClassHierarchyResolverOptionImpl(ClassHierarchyResolver.defaultResolver()), + null // _ -> null + ); @SuppressWarnings("unchecked") @Override @@ -85,6 +104,8 @@ public ClassFileImpl withOptions(Option... options) { for (var o : options) { if (o instanceof StackMapsOption oo) { smo = oo; + } else if (o instanceof ClassHierarchyResolverOption oo) { + chro = oo; } else if (o instanceof DebugElementsOption oo) { deo = oo; } else if (o instanceof LineNumbersOption oo) { @@ -99,8 +120,6 @@ public ClassFileImpl withOptions(Option... options) { dco = oo; } else if (o instanceof DeadLabelsOption oo) { dlo = oo; - } else if (o instanceof ClassHierarchyResolverOption oo) { - chro = oo; } else if (o instanceof AttributeMapperOption oo) { amo = oo; } else { // null or unknown Option type @@ -127,9 +146,8 @@ public byte[] build(ClassEntry thisClassEntry, @Override public byte[] transformClass(ClassModel model, ClassEntry newClassName, ClassTransform transform) { - ConstantPoolBuilder constantPool = constantPoolSharingOption() == ConstantPoolSharingOption.SHARED_POOL - ? ConstantPoolBuilder.of(model) - : ConstantPoolBuilder.of(); + ConstantPoolBuilder constantPool = sharedConstantPool() ? ConstantPoolBuilder.of(model) + : ConstantPoolBuilder.of(); return build(newClassName, constantPool, new Consumer() { @Override @@ -141,10 +159,14 @@ public void accept(ClassBuilder builder) { }); } + public boolean sharedConstantPool() { + return constantPoolSharingOption == null || constantPoolSharingOption == ConstantPoolSharingOption.SHARED_POOL; + } + @Override public List verify(ClassModel model) { try { - return VerifierImpl.verify(model, classHierarchyResolverOption().classHierarchyResolver(), null); + return VerifierImpl.verify(model, classHierarchyResolver(), null); } catch (IllegalArgumentException verifierInitializationError) { return List.of(new VerifyError(verifierInitializationError.getMessage())); } @@ -159,6 +181,58 @@ public List verify(byte[] bytes) { } } + public Function> attributeMapper() { + if (attributeMapperOption == null) { + return _ -> null; + } else { + return ((AttributeMapperOption)attributeMapperOption).attributeMapper(); + } + } + + public ClassHierarchyResolver classHierarchyResolver() { + if (classHierarchyResolverOption == null) { + return ClassHierarchyImpl.DEFAULT_RESOLVER; + } else { + return ((ClassHierarchyResolverOption)classHierarchyResolverOption).classHierarchyResolver(); + } + } + + public boolean dropDeadLabels() { + return (deadLabelsOption != null && deadLabelsOption == DeadLabelsOption.DROP_DEAD_LABELS); + } + + public boolean passDebugElements() { + return (debugElementsOption == null || debugElementsOption == DebugElementsOption.PASS_DEBUG); + } + + public boolean passLineNumbers() { + return (lineNumbersOption == null || lineNumbersOption == LineNumbersOption.PASS_LINE_NUMBERS); + } + + public AttributesProcessingOption attributesProcessingOption() { + return (attributesProcessingOption == null) ? AttributesProcessingOption.PASS_ALL_ATTRIBUTES : (AttributesProcessingOption)attributesProcessingOption; + } + + public boolean fixShortJumps() { + return (shortJumpsOption == null || shortJumpsOption == ShortJumpsOption.FIX_SHORT_JUMPS); + } + + public boolean stackMapsWhenRequired() { + return (stackMapsOption == null || stackMapsOption == StackMapsOption.STACK_MAPS_WHEN_REQUIRED); + } + + public boolean generateStackMaps() { + return (stackMapsOption == StackMapsOption.GENERATE_STACK_MAPS); + } + + public boolean dropStackMaps() { + return (stackMapsOption == StackMapsOption.DROP_STACK_MAPS); + } + + public boolean patchDeadCode() { + return (deadCodeOption == null || deadCodeOption == DeadCodeOption.PATCH_DEAD_CODE); + } + public record AttributeMapperOptionImpl(Function> attributeMapper) implements AttributeMapperOption { } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index 9695b16ad51..6a4b0cd486f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -82,7 +82,7 @@ public final class ClassReaderImpl this.buffer = classfileBytes; this.classfileLength = classfileBytes.length; this.context = context; - this.attributeMapper = this.context.attributeMapperOption().attributeMapper(); + this.attributeMapper = this.context.attributeMapper(); if (classfileLength < 4 || readInt(0) != 0xCAFEBABE) { throw new IllegalArgumentException("Bad magic number"); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index 68c93249c1b..e08d2b76479 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -122,7 +122,7 @@ private void inflateMetadata() { if (!inflated) { if (labels == null) labels = new LabelImpl[codeLength + 1]; - if (classReader.context().lineNumbersOption() == ClassFile.LineNumbersOption.PASS_LINE_NUMBERS) + if (classReader.context().passLineNumbers()) inflateLineNumbers(); inflateJumpTargets(); inflateTypeAnnotations(); @@ -167,7 +167,7 @@ public void forEach(Consumer consumer) { inflateMetadata(); boolean doLineNumbers = (lineNumbers != null); generateCatchTargets(consumer); - if (classReader.context().debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG) + if (classReader.context().passDebugElements()) generateDebugElements(consumer); for (int pos=codeStart; pos br.target(); case DiscontinuedInstruction.JsrInstruction jsr -> jsr.target(); + case LookupSwitchInstruction ls -> { + ls.defaultTarget(); + ls.cases(); + } + case TableSwitchInstruction ts -> { + ts.defaultTarget(); + ts.cases(); + } default -> {} } pos += i.sizeInBytes(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 0d61895fe9f..7d67ed272af 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -25,8 +25,10 @@ package jdk.internal.classfile.impl; +import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -82,18 +84,39 @@ public ClassBuilder with(ClassElement element) { return this; } + @Override + public ClassBuilder withFlags(int flags) { + setFlags(flags); + return this; + } + + @Override + public ClassBuilder withField(String name, + ClassDesc descriptor, + int flags) { + return withField(new DirectFieldBuilder(constantPool, context, + constantPool.utf8Entry(name), constantPool.utf8Entry(descriptor), flags, null)); + } + + @Override + public ClassBuilder withField(Utf8Entry name, + Utf8Entry descriptor, + int flags) { + return withField(new DirectFieldBuilder(constantPool, context, name, descriptor, flags, null)); + } + @Override public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { - return withField(new DirectFieldBuilder(constantPool, context, name, descriptor, null) + return withField(new DirectFieldBuilder(constantPool, context, name, descriptor, 0, null) .run(handler)); } @Override public ClassBuilder transformField(FieldModel field, FieldTransform transform) { DirectFieldBuilder builder = new DirectFieldBuilder(constantPool, context, field.fieldName(), - field.fieldType(), field); + field.fieldType(), 0, field); builder.transform(field, transform); return withField(builder); } @@ -192,7 +215,7 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC boolean written = constantPool.writeBootstrapMethods(tail); if (written) { // Update attributes count - tail.patchInt(attributesOffset, 2, attributes.size() + 1); + tail.patchU2(attributesOffset, attributes.size() + 1); } // Now we can make the head diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 1b950f28d00..a9be0695911 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -103,7 +103,7 @@ public static UnboundAttribute build(MethodInfo methodInfo, handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, false)); cb.buildContent(); } catch (LabelOverflowException loe) { - if (context.shortJumpsOption() == ClassFile.ShortJumpsOption.FIX_SHORT_JUMPS) { + if (context.fixShortJumps()) { handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, true)); cb.buildContent(); } @@ -122,7 +122,7 @@ private DirectCodeBuilder(MethodInfo methodInfo, setOriginal(original); this.methodInfo = methodInfo; this.transformFwdJumps = transformFwdJumps; - this.transformBackJumps = context.shortJumpsOption() == ClassFile.ShortJumpsOption.FIX_SHORT_JUMPS; + this.transformBackJumps = context.fixShortJumps(); bytecodesBufWriter = (original instanceof CodeImpl cai) ? new BufWriterImpl(constantPool, context, cai.codeLength()) : new BufWriterImpl(constantPool, context); this.startLabel = new LabelImpl(this, 0); @@ -195,7 +195,7 @@ private void writeExceptionHandlers(BufWriterImpl buf) { int endPc = labelToBci(h.tryEnd()); int handlerPc = labelToBci(h.handler()); if (startPc == -1 || endPc == -1 || handlerPc == -1) { - if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + if (context.dropDeadLabels()) { handlersSize--; } else { throw new IllegalArgumentException("Unbound label in exception handler"); @@ -209,7 +209,7 @@ private void writeExceptionHandlers(BufWriterImpl buf) { } } if (handlersSize < handlers.size()) - buf.patchInt(pos, 2, handlersSize); + buf.patchU2(pos, handlersSize); } private void buildContent() { @@ -219,7 +219,7 @@ private void buildContent() { // Backfill branches for which Label didn't have position yet processDeferredLabels(); - if (context.debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG) { + if (context.passDebugElements()) { if (!characterRanges.isEmpty()) { Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) { @@ -232,7 +232,7 @@ public void writeBody(BufWriterImpl b) { var start = labelToBci(cr.startScope()); var end = labelToBci(cr.endScope()); if (start == -1 || end == -1) { - if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + if (context.dropDeadLabels()) { crSize--; } else { throw new IllegalArgumentException("Unbound label in character range"); @@ -246,7 +246,7 @@ public void writeBody(BufWriterImpl b) { } } if (crSize < characterRanges.size()) - b.patchInt(pos, 2, crSize); + b.patchU2(pos, crSize); } }; attributes.withAttribute(a); @@ -261,7 +261,7 @@ public void writeBody(BufWriterImpl b) { b.writeU2(lvSize); for (LocalVariable l : localVariables) { if (!Util.writeLocalVariable(b, l)) { - if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + if (context.dropDeadLabels()) { lvSize--; } else { throw new IllegalArgumentException("Unbound label in local variable type"); @@ -269,7 +269,7 @@ public void writeBody(BufWriterImpl b) { } } if (lvSize < localVariables.size()) - b.patchInt(pos, 2, lvSize); + b.patchU2(pos, lvSize); } }; attributes.withAttribute(a); @@ -284,7 +284,7 @@ public void writeBody(BufWriterImpl b) { b.writeU2(localVariableTypes.size()); for (LocalVariableType l : localVariableTypes) { if (!Util.writeLocalVariable(b, l)) { - if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + if (context.dropDeadLabels()) { lvtSize--; } else { throw new IllegalArgumentException("Unbound label in local variable type"); @@ -292,7 +292,7 @@ public void writeBody(BufWriterImpl b) { } } if (lvtSize < localVariableTypes.size()) - b.patchInt(pos, 2, lvtSize); + b.patchU2(pos, lvtSize); } }; attributes.withAttribute(a); @@ -357,24 +357,21 @@ public void writeBody(BufWriterImpl buf) { } if (codeAndExceptionsMatch(codeLength)) { - switch (context.stackMapsOption()) { - case STACK_MAPS_WHEN_REQUIRED -> { - attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null)); - writeCounters(true, buf); - } - case GENERATE_STACK_MAPS -> - generateStackMaps(buf); - case DROP_STACK_MAPS -> - writeCounters(true, buf); + if (context.stackMapsWhenRequired()) { + attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null)); + writeCounters(true, buf); + } else if (context.generateStackMaps()) { + generateStackMaps(buf); + } else if (context.dropStackMaps()) { + writeCounters(true, buf); } } else { - switch (context.stackMapsOption()) { - case STACK_MAPS_WHEN_REQUIRED -> - tryGenerateStackMaps(false, buf); - case GENERATE_STACK_MAPS -> - generateStackMaps(buf); - case DROP_STACK_MAPS -> - writeCounters(false, buf); + if (context.stackMapsWhenRequired()) { + tryGenerateStackMaps(false, buf); + } else if (context.generateStackMaps()) { + generateStackMaps(buf); + } else if (context.dropStackMaps()) { + writeCounters(false, buf); } } @@ -455,8 +452,7 @@ private record DeferredLabel(int labelPc, int size, int instructionPc, Label lab private void writeLabelOffset(int nBytes, int instructionPc, Label label) { int targetBci = labelToBci(label); if (targetBci == -1) { - int pc = curPc(); - bytecodesBufWriter.writeIntBytes(nBytes, 0); + int pc = bytecodesBufWriter.skip(nBytes); if (deferredLabels == null) deferredLabels = new ArrayList<>(); deferredLabels.add(new DeferredLabel(pc, nBytes, instructionPc, label)); @@ -472,8 +468,13 @@ private void processDeferredLabels() { if (deferredLabels != null) { for (DeferredLabel dl : deferredLabels) { int branchOffset = labelToBci(dl.label) - dl.instructionPc; - if (dl.size == 2 && (short)branchOffset != branchOffset) throw new LabelOverflowException(); - bytecodesBufWriter.patchInt(dl.labelPc, dl.size, branchOffset); + if (dl.size == 2) { + if ((short)branchOffset != branchOffset) throw new LabelOverflowException(); + bytecodesBufWriter.patchU2(dl.labelPc, branchOffset); + } else { + assert dl.size == 4; + bytecodesBufWriter.patchInt(dl.labelPc, branchOffset); + } } } } @@ -543,11 +544,11 @@ public void writeLookupSwitch(Label defaultTarget, List cases) { writeBytecode(LOOKUPSWITCH); int pad = 4 - (curPc() % 4); if (pad != 4) - bytecodesBufWriter.writeIntBytes(pad, 0); + bytecodesBufWriter.skip(pad); // padding content can be anything writeLabelOffset(4, instructionPc, defaultTarget); bytecodesBufWriter.writeInt(cases.size()); cases = new ArrayList<>(cases); - cases.sort(new Comparator() { + cases.sort(new Comparator<>() { @Override public int compare(SwitchCase c1, SwitchCase c2) { return Integer.compare(c1.caseValue(), c2.caseValue()); @@ -564,7 +565,7 @@ public void writeTableSwitch(int low, int high, Label defaultTarget, List handler) { return this; } + @Override + public FieldBuilder withFlags(int flags) { + setFlags(flags); + return this; + } + void setFlags(int flags) { this.flags = flags; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java index f79eb0af0cb..fac6b7384e2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java @@ -61,6 +61,12 @@ public DirectMethodBuilder(SplitConstantPool constantPool, this.flags = flags; } + @Override + public MethodBuilder withFlags(int flags) { + setFlags(flags); + return this; + } + void setFlags(int flags) { boolean wasStatic = (this.flags & ClassFile.ACC_STATIC) != 0; boolean isStatic = (flags & ClassFile.ACC_STATIC) != 0; @@ -98,6 +104,9 @@ public int methodFlags() { @Override public int parameterSlot(int paramNo) { + if (paramNo == 0) { + return ((flags & ClassFile.ACC_STATIC) != 0) ? 0 : 1; + } if (parameterSlots == null) parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol()); return parameterSlots[paramNo]; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java index 3e5d66245f0..860b7e74b4d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,23 +24,66 @@ */ package jdk.internal.classfile.impl; -import java.nio.ByteBuffer; -import static java.lang.classfile.ClassFile.ASTORE_3; -import static java.lang.classfile.ClassFile.ISTORE; -import static java.lang.classfile.ClassFile.LOOKUPSWITCH; -import static java.lang.classfile.ClassFile.TABLESWITCH; -import static java.lang.classfile.ClassFile.WIDE; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +import jdk.internal.misc.Unsafe; +import jdk.internal.util.Preconditions; +import jdk.internal.vm.annotation.Stable; + +import static java.lang.classfile.ClassFile.*; public final class RawBytecodeHelper { + public static final BiFunction, IllegalArgumentException> + IAE_FORMATTER = Preconditions.outOfBoundsExceptionFormatter(new Function<>() { + @Override + public IllegalArgumentException apply(String s) { + return new IllegalArgumentException(s); + } + }); + + public record CodeRange(byte[] array, int length) { + public RawBytecodeHelper start() { + return new RawBytecodeHelper(this); + } + } + public static final int ILLEGAL = -1; - private static final byte[] LENGTHS = new byte[] { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 3, 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 | (6 << 4), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2 | (4 << 4), 0, 0, 1, 1, 1, - 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3, 5, 5, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 4, 4, 4, 2, 4, 3, 3, 0, 0, 1, 3, 2, 3, 3, 3, 1, 2, 1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + /** + * The length of opcodes, or -1 for no fixed length. + * This is generated as if: + * {@snippet lang=java : + * var lengths = new byte[0x100]; + * Arrays.fill(lengths, (byte) -1); + * for (var op : Opcode.values()) { + * if (!op.isWide()) { + * lengths[op.bytecode()] = (byte) op.sizeIfFixed(); + * } + * } + * } + * Tested in UtilTest::testOpcodeLengthTable. + */ + // Note: Consider distinguishing non-opcode and non-fixed-length opcode + public static final @Stable byte[] LENGTHS = new byte[] { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, -1, -1, 1, 1, 1, 1, + 1, 1, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, + 3, 3, 1, 1, -1, 4, 3, 3, 5, 5, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; public static boolean isStoreIntoLocal(int code) { @@ -51,121 +94,200 @@ public static int align(int n) { return (n + 3) & ~3; } - private final ByteBuffer bytecode; - public int bci, nextBci, endBci; - public int rawCode; - public boolean isWide; + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + public final CodeRange code; + private int nextBci; + private int bci; + private int opcode; + private boolean isWide; - public RawBytecodeHelper(ByteBuffer bytecode) { - this.bytecode = bytecode; - this.bci = 0; - this.nextBci = 0; - this.endBci = bytecode.capacity(); + public static CodeRange of(byte[] array) { + return new CodeRange(array, array.length); } - public boolean isLastBytecode() { - return nextBci >= endBci; + public static CodeRange of(byte[] array, int limit) { + return new CodeRange(array, limit); } - public int getShort(int bci) { - return bytecode.getShort(bci); + private RawBytecodeHelper(CodeRange range) { + this.code = range; } - public int dest() { - return bci + getShort(bci + 1); + // immutable states + + /** {@return the end of the code array} */ + public int endBci() { + return code.length; } - public int getInt(int bci) { - return bytecode.getInt(bci); + // setup + + /** + * Sets the starting bci for bytecode reading. Can be set to + * {@link #endBci} to end scanning. Must be followed by a + * {@link #next} before getter access. + */ + public void reset(int nextBci) { + Preconditions.checkIndex(nextBci, endBci() + 1, IAE_FORMATTER); + this.nextBci = nextBci; } - public int destW() { - return bci + getInt(bci + 1); + // getters after transition + + /** + * Returns the current functional opcode, or {@link #ILLEGAL} if + * the next instruction is invalid in format. + * If this returns a valid opcode, that instruction's format must + * be valid and can be accessed unchecked. + */ + public int opcode() { + return opcode; } - public int getIndexU1() { - return bytecode.get(bci + 1) & 0xff; + /** + * Returns whether the current functional opcode is in wide. + */ + public boolean isWide() { + return isWide; } + /** + * Returns the last validated instruction's index. + */ + public int bci() { + return bci; + } + + // general utilities + public int getU1(int bci) { - return bytecode.get(bci) & 0xff; + Preconditions.checkIndex(bci, endBci(), IAE_FORMATTER); + return getU1Unchecked(bci); } - public int rawNext(int jumpTo) { - this.nextBci = jumpTo; - return rawNext(); + public int getU2(int bci) { + Preconditions.checkFromIndexSize(bci, 2, endBci(), IAE_FORMATTER); + return getU2Unchecked(bci); } - public int rawNext() { - bci = nextBci; - int code = bytecode.get(bci) & 0xff; - int len = LENGTHS[code] & 0xf; - if (len > 0 && (bci <= endBci - len)) { - isWide = false; - nextBci += len; - if (nextBci <= bci) { - code = ILLEGAL; - } - rawCode = code; - return code; - } else { - len = switch (bytecode.get(bci) & 0xff) { - case WIDE -> { - if (bci + 1 >= endBci) { - yield -1; - } - yield LENGTHS[bytecode.get(bci + 1) & 0xff] >> 4; - } - case TABLESWITCH -> { - int aligned_bci = align(bci + 1); - if (aligned_bci + 3 * 4 >= endBci) { - yield -1; - } - int lo = bytecode.getInt(aligned_bci + 1 * 4); - int hi = bytecode.getInt(aligned_bci + 2 * 4); - int l = aligned_bci - bci + (3 + hi - lo + 1) * 4; - if (l > 0) yield l; else yield -1; - } - case LOOKUPSWITCH -> { - int aligned_bci = align(bci + 1); - if (aligned_bci + 2 * 4 >= endBci) { - yield -1; - } - int npairs = bytecode.getInt(aligned_bci + 4); - int l = aligned_bci - bci + (2 + 2 * npairs) * 4; - if (l > 0) yield l; else yield -1; - } - default -> - 0; - }; - if (len <= 0 || (bci > endBci - len) || (bci - len >= nextBci)) { - code = ILLEGAL; - } else { - nextBci += len; - isWide = false; - if (code == WIDE) { - if (bci + 1 >= endBci) { - code = ILLEGAL; - } else { - code = bytecode.get(bci + 1) & 0xff; - isWide = true; - } - } - } - rawCode = code; - return code; - } + public int getShort(int bci) { + Preconditions.checkFromIndexSize(bci, 2, endBci(), IAE_FORMATTER); + return getShortUnchecked(bci); + } + + public int getInt(int bci) { + Preconditions.checkFromIndexSize(bci, 4, endBci(), IAE_FORMATTER); + return getIntUnchecked(bci); + } + + // Unchecked accessors: only if opcode() is validated + + public int getU1Unchecked(int bci) { + return Byte.toUnsignedInt(code.array[bci]); + } + + public int getU2Unchecked(int bci) { + return UNSAFE.getCharUnaligned(code.array, (long) Unsafe.ARRAY_BYTE_BASE_OFFSET + bci, true); } + public int getShortUnchecked(int bci) { + return UNSAFE.getShortUnaligned(code.array, (long) Unsafe.ARRAY_BYTE_BASE_OFFSET + bci, true); + } + + // used after switch validation + public int getIntUnchecked(int bci) { + return UNSAFE.getIntUnaligned(code.array, (long) Unsafe.ARRAY_BYTE_BASE_OFFSET + bci, true); + } + + // non-wide branches + public int dest() { + return bci + getShortUnchecked(bci + 1); + } + + // goto_w and jsr_w + public int destW() { + return bci + getIntUnchecked(bci + 1); + } + + // *load, *store, iinc public int getIndex() { - return (isWide) ? getIndexU2Raw(bci + 2) : getIndexU1(); + return isWide ? getU2Unchecked(bci + 2) : getIndexU1(); } + // ldc + public int getIndexU1() { + return getU1Unchecked(bci + 1); + } + + // usually cp entry index public int getIndexU2() { - return getIndexU2Raw(bci + 1); + return getU2Unchecked(bci + 1); } - public int getIndexU2Raw(int bci) { - return bytecode.getShort(bci) & 0xffff; + // Transition methods + + /** + * Transitions to the next instruction and returns whether scanning should + * continue. If the next instruction is malformed, {@link #opcode()} returns + * {@link #ILLEGAL}, so we can perform value access without bound checks if + * we have a valid opcode. + */ + public boolean next() { + var bci = nextBci; + var end = endBci(); + if (bci >= end) { + return false; + } + + int code = getU1Unchecked(bci); + int len = LENGTHS[code & 0xFF]; // & 0xFF eliminates bound check + this.bci = bci; + opcode = code; + isWide = false; + if (len <= 0) { + len = checkSpecialInstruction(bci, end, code); // sets opcode + } + + if (len <= 0 || (nextBci += len) > end) { + opcode = ILLEGAL; + } + + return true; + } + + // Put rarely used code in another method to reduce code size + private int checkSpecialInstruction(int bci, int end, int code) { + if (code == WIDE) { + if (bci + 1 >= end) { + return -1; + } + opcode = code = getIndexU1(); + isWide = true; + // Validated in UtilTest.testOpcodeLengthTable + return LENGTHS[code] * 2; + } + if (code == TABLESWITCH) { + int alignedBci = align(bci + 1); + if (alignedBci + 3 * 4 >= end) { + return -1; + } + int lo = getIntUnchecked(alignedBci + 1 * 4); + int hi = getIntUnchecked(alignedBci + 2 * 4); + long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L; + return l > 0 && ((int) l == l) ? (int) l : -1; + } + if (code == LOOKUPSWITCH) { + int alignedBci = align(bci + 1); + if (alignedBci + 2 * 4 >= end) { + return -1; + } + int npairs = getIntUnchecked(alignedBci + 4); + if (npairs < 0) { + return -1; + } + long l = alignedBci - bci + (2L + 2L * npairs) * 4L; + return l > 0 && ((int) l == l) ? (int) l : -1; + } + return -1; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 777da61c49d..4f48c8b731d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -142,8 +142,8 @@ public boolean writeBootstrapMethods(BufWriterImpl buf) { for (int i = parentBsmSize; i < bsmSize; i++) bootstrapMethodEntry(i).writeTo(buf); int attrLen = buf.size() - pos; - buf.patchInt(pos + 2, 4, attrLen - 6); - buf.patchInt(pos + 6, 2, bsmSize); + buf.patchInt(pos + 2, attrLen - 6); + buf.patchU2(pos + 6, bsmSize); } else { UnboundAttribute a diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java index 861bb509420..783ff4bf106 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java @@ -34,7 +34,6 @@ import java.lang.classfile.constantpool.MemberRefEntry; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; -import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.BitSet; import java.util.List; @@ -55,7 +54,7 @@ static StackCounter of(DirectCodeBuilder dcb, BufWriterImpl buf) { dcb.methodInfo.methodName().stringValue(), dcb.methodInfo.methodTypeSymbol(), (dcb.methodInfo.methodFlags() & ACC_STATIC) != 0, - dcb.bytecodesBufWriter.asByteBuffer(), + dcb.bytecodesBufWriter.bytecodeView(), dcb.constantPool, dcb.handlers); } @@ -67,7 +66,6 @@ static StackCounter of(DirectCodeBuilder dcb, BufWriterImpl buf) { private final String methodName; private final MethodTypeDesc methodDesc; private final boolean isStatic; - private final ByteBuffer bytecode; private final SplitConstantPool cp; private final Queue targets; private final BitSet visited; @@ -91,12 +89,12 @@ private boolean next() { Target en; while ((en = targets.poll()) != null) { if (!visited.get(en.bci)) { - bcs.nextBci = en.bci; + bcs.reset(en.bci); stack = en.stack; return true; } } - bcs.nextBci = bcs.endBci; + bcs.reset(bcs.endBci()); return false; } @@ -106,14 +104,13 @@ public StackCounter(LabelContext labelContext, String methodName, MethodTypeDesc methodDesc, boolean isStatic, - ByteBuffer bytecode, + RawBytecodeHelper.CodeRange bytecode, SplitConstantPool cp, List handlers) { this.thisClass = thisClass; this.methodName = methodName; this.methodDesc = methodDesc; this.isStatic = isStatic; - this.bytecode = bytecode; this.cp = cp; targets = new ArrayDeque<>(); stack = rets = 0; @@ -132,14 +129,13 @@ public StackCounter(LabelContext labelContext, } maxLocals = isStatic ? 0 : 1; maxLocals += Util.parameterSlots(methodDesc); - bcs = new RawBytecodeHelper(bytecode); - visited = new BitSet(bcs.endBci); + bcs = bytecode.start(); + visited = new BitSet(bcs.endBci()); targets.add(new Target(0, 0)); while (next()) { - while (!bcs.isLastBytecode()) { - bcs.rawNext(); - int opcode = bcs.rawCode; - int bci = bcs.bci; + while (bcs.next()) { + int opcode = bcs.opcode(); + int bci = bcs.bci(); visited.set(bci); switch (opcode) { case NOP, LALOAD, DALOAD, SWAP, INEG, ARRAYLENGTH, INSTANCEOF, LNEG, FNEG, DNEG, I2F, L2D, F2I, D2L, I2B, I2C, I2S, @@ -267,12 +263,12 @@ public StackCounter(LabelContext labelContext, } case TABLESWITCH, LOOKUPSWITCH -> { int alignedBci = RawBytecodeHelper.align(bci + 1); - int defaultOfset = bcs.getInt(alignedBci); + int defaultOffset = bcs.getIntUnchecked(alignedBci); int keys, delta; addStackSlot(-1); - if (bcs.rawCode == TABLESWITCH) { - int low = bcs.getInt(alignedBci + 4); - int high = bcs.getInt(alignedBci + 2 * 4); + if (bcs.opcode() == TABLESWITCH) { + int low = bcs.getIntUnchecked(alignedBci + 4); + int high = bcs.getIntUnchecked(alignedBci + 2 * 4); if (low > high) { throw error("low must be less than or equal to high in tableswitch"); } @@ -282,24 +278,23 @@ public StackCounter(LabelContext labelContext, } delta = 1; } else { - keys = bcs.getInt(alignedBci + 4); + keys = bcs.getIntUnchecked(alignedBci + 4); if (keys < 0) { throw error("number of keys in lookupswitch less than 0"); } delta = 2; for (int i = 0; i < (keys - 1); i++) { - int this_key = bcs.getInt(alignedBci + (2 + 2 * i) * 4); - int next_key = bcs.getInt(alignedBci + (2 + 2 * i + 2) * 4); + int this_key = bcs.getIntUnchecked(alignedBci + (2 + 2 * i) * 4); + int next_key = bcs.getIntUnchecked(alignedBci + (2 + 2 * i + 2) * 4); if (this_key >= next_key) { throw error("Bad lookupswitch instruction"); } } } - int target = bci + defaultOfset; + int target = bci + defaultOffset; jump(target); for (int i = 0; i < keys; i++) { - alignedBci = RawBytecodeHelper.align(bcs.bci + 1); - target = bci + bcs.getInt(alignedBci + (3 + i * delta) * 4); + target = bci + bcs.getIntUnchecked(alignedBci + (3 + i * delta) * 4); jump(target); } next(); @@ -314,7 +309,7 @@ public StackCounter(LabelContext labelContext, } case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD -> { var tk = TypeKind.fromDescriptor(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).nameAndType().type()); - switch (bcs.rawCode) { + switch (bcs.opcode()) { case GETSTATIC -> addStackSlot(tk.slotSize()); case PUTSTATIC -> @@ -337,7 +332,7 @@ public StackCounter(LabelContext labelContext, addStackSlot(delta); } case MULTIANEWARRAY -> - addStackSlot(1 - bcs.getU1(bcs.bci + 3)); + addStackSlot(1 - bcs.getU1Unchecked(bcs.bci() + 3)); case JSR -> { addStackSlot(+1); jump(bcs.dest()); //here we lost track of the exact stack size after return from subroutine @@ -395,10 +390,10 @@ private void processLdc(int index) { private IllegalArgumentException error(String msg) { var sb = new StringBuilder("%s at bytecode offset %d of method %s(%s)".formatted( msg, - bcs.bci, + bcs.bci(), methodName, methodDesc.parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(",")))); - Util.dumpMethod(cp, thisClass, methodName, methodDesc, isStatic ? ACC_STATIC : 0, bytecode, sb::append); + Util.dumpMethod(cp, thisClass, methodName, methodDesc, isStatic ? ACC_STATIC : 0, bcs.code, sb::append); return new IllegalArgumentException(sb.toString()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 514c1d32f41..c6564c289d6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -38,7 +38,6 @@ import java.lang.classfile.constantpool.MemberRefEntry; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; @@ -46,6 +45,7 @@ import java.util.Objects; import java.util.stream.Collectors; import jdk.internal.constant.ReferenceClassDescImpl; +import jdk.internal.util.Preconditions; import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.*; @@ -152,7 +152,7 @@ static StackMapGenerator of(DirectCodeBuilder dcb, BufWriterImpl buf) { dcb.methodInfo.methodName().stringValue(), dcb.methodInfo.methodTypeSymbol(), (dcb.methodInfo.methodFlags() & ACC_STATIC) != 0, - dcb.bytecodesBufWriter.asByteBuffer(), + dcb.bytecodesBufWriter.bytecodeView(), dcb.constantPool, dcb.context, dcb.handlers); @@ -188,7 +188,7 @@ static record RawExceptionCatch(int start, int end, int handler, Type catchType) private final Type thisType; private final String methodName; private final MethodTypeDesc methodDesc; - private final ByteBuffer bytecode; + private final RawBytecodeHelper.CodeRange bytecode; private final SplitConstantPool cp; private final boolean isStatic; private final LabelContext labelContext; @@ -222,7 +222,7 @@ public StackMapGenerator(LabelContext labelContext, String methodName, MethodTypeDesc methodDesc, boolean isStatic, - ByteBuffer bytecode, + RawBytecodeHelper.CodeRange bytecode, SplitConstantPool cp, ClassFileImpl context, List handlers) { @@ -235,9 +235,9 @@ public StackMapGenerator(LabelContext labelContext, this.labelContext = labelContext; this.handlers = handlers; this.rawHandlers = new ArrayList<>(handlers.size()); - this.classHierarchy = new ClassHierarchyImpl(context.classHierarchyResolverOption().classHierarchyResolver()); - this.patchDeadCode = context.deadCodeOption() == ClassFile.DeadCodeOption.PATCH_DEAD_CODE; - this.filterDeadLabels = context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS; + this.classHierarchy = new ClassHierarchyImpl(context.classHierarchyResolver()); + this.patchDeadCode = context.patchDeadCode(); + this.filterDeadLabels = context.dropDeadLabels(); this.currentFrame = new Frame(classHierarchy); generate(); } @@ -289,7 +289,7 @@ private boolean isAnyFrameDirty() { } private void generate() { - exMin = bytecode.capacity(); + exMin = bytecode.length(); exMax = -1; for (var exhandler : handlers) { int start_pc = labelContext.labelToBci(exhandler.tryStart()); @@ -326,15 +326,13 @@ private void generate() { //patch frame frame.pushStack(Type.THROWABLE_TYPE); if (maxStack < 1) maxStack = 1; - int blockSize = (i < framesCount - 1 ? frames.get(i + 1).offset : bytecode.limit()) - frame.offset; + int end = (i < framesCount - 1 ? frames.get(i + 1).offset : bytecode.length()) - 1; //patch bytecode - bytecode.position(frame.offset); - for (int n=1; n bcs.bci) { + if (ncf && thisOffset > bcs.bci()) { throw generatorError("Expecting a stack map frame"); } - if (thisOffset == bcs.bci) { + if (thisOffset == bcs.bci()) { if (!ncf) { currentFrame.checkAssignableTo(frames.get(stackmapIndex)); } @@ -426,11 +423,12 @@ private void processMethod() { if (stackmapIndex == frames.size()) return; //skip the rest of this round nextFrame = frames.get(stackmapIndex++); } - bcs.rawNext(nextFrame.offset); //skip code up-to the next frame - currentFrame.offset = bcs.bci; + bcs.reset(nextFrame.offset); //skip code up-to the next frame + bcs.next(); + currentFrame.offset = bcs.bci(); currentFrame.copyFrom(nextFrame); nextFrame.dirty = false; - } else if (thisOffset < bcs.bci) { + } else if (thisOffset < bcs.bci()) { throw new ClassFormatError(String.format("Bad stack map offset %d", thisOffset)); } } else if (ncf) { @@ -441,11 +439,11 @@ private void processMethod() { } private boolean processBlock(RawBytecodeHelper bcs) { - int opcode = bcs.rawCode; + int opcode = bcs.opcode(); boolean ncf = false; boolean this_uninit = false; boolean verified_exc_handlers = false; - int bci = bcs.bci; + int bci = bcs.bci(); Type type1, type2, type3, type4; if (RawBytecodeHelper.isStoreIntoLocal(opcode) && bci >= exMin && bci < exMax) { processExceptionHandlerTargets(bci, this_uninit); @@ -651,7 +649,7 @@ private boolean processBlock(RawBytecodeHelper bcs) { currentFrame.decStack(1).pushStack(cpIndexToType(bcs.getIndexU2(), cp)); case MULTIANEWARRAY -> { type1 = cpIndexToType(bcs.getIndexU2(), cp); - int dim = bcs.getU1(bcs.bci + 3); + int dim = bcs.getU1Unchecked(bcs.bci() + 3); for (int i = 0; i < dim; i++) { currentFrame.popStack(); } @@ -708,14 +706,14 @@ private void processLdc(int index) { } private void processSwitch(RawBytecodeHelper bcs) { - int bci = bcs.bci; + int bci = bcs.bci(); int alignedBci = RawBytecodeHelper.align(bci + 1); - int defaultOfset = bcs.getInt(alignedBci); + int defaultOffset = bcs.getIntUnchecked(alignedBci); int keys, delta; currentFrame.popStack(); - if (bcs.rawCode == TABLESWITCH) { - int low = bcs.getInt(alignedBci + 4); - int high = bcs.getInt(alignedBci + 2 * 4); + if (bcs.opcode() == TABLESWITCH) { + int low = bcs.getIntUnchecked(alignedBci + 4); + int high = bcs.getIntUnchecked(alignedBci + 2 * 4); if (low > high) { throw generatorError("low must be less than or equal to high in tableswitch"); } @@ -725,31 +723,30 @@ private void processSwitch(RawBytecodeHelper bcs) { } delta = 1; } else { - keys = bcs.getInt(alignedBci + 4); + keys = bcs.getIntUnchecked(alignedBci + 4); if (keys < 0) { throw generatorError("number of keys in lookupswitch less than 0"); } delta = 2; for (int i = 0; i < (keys - 1); i++) { - int this_key = bcs.getInt(alignedBci + (2 + 2 * i) * 4); - int next_key = bcs.getInt(alignedBci + (2 + 2 * i + 2) * 4); + int this_key = bcs.getIntUnchecked(alignedBci + (2 + 2 * i) * 4); + int next_key = bcs.getIntUnchecked(alignedBci + (2 + 2 * i + 2) * 4); if (this_key >= next_key) { throw generatorError("Bad lookupswitch instruction"); } } } - int target = bci + defaultOfset; + int target = bci + defaultOffset; checkJumpTarget(currentFrame, target); for (int i = 0; i < keys; i++) { - alignedBci = RawBytecodeHelper.align(bcs.bci + 1); - target = bci + bcs.getInt(alignedBci + (3 + i * delta) * 4); + target = bci + bcs.getIntUnchecked(alignedBci + (3 + i * delta) * 4); checkJumpTarget(currentFrame, target); } } private void processFieldInstructions(RawBytecodeHelper bcs) { var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).nameAndType()); - switch (bcs.rawCode) { + switch (bcs.opcode()) { case GETSTATIC -> currentFrame.pushStack(desc); case PUTSTATIC -> { @@ -771,13 +768,13 @@ private void processFieldInstructions(RawBytecodeHelper bcs) { private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBlock, boolean thisUninit) { int index = bcs.getIndexU2(); - int opcode = bcs.rawCode; + int opcode = bcs.opcode(); var nameAndType = opcode == INVOKEDYNAMIC ? cp.entryByIndex(index, InvokeDynamicEntry.class).nameAndType() : cp.entryByIndex(index, MemberRefEntry.class).nameAndType(); String invokeMethodName = nameAndType.name().stringValue(); var mDesc = Util.methodTypeSymbol(nameAndType); - int bci = bcs.bci; + int bci = bcs.bci(); currentFrame.decStack(Util.parameterSlots(mDesc)); if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { if (OBJECT_INITIALIZER_NAME.equals(invokeMethodName)) { @@ -790,7 +787,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl thisUninit = true; } else if (type.tag == ITEM_UNINITIALIZED) { int new_offset = type.bci; - int new_class_index = bcs.getIndexU2Raw(new_offset + 1); + int new_class_index = bcs.getU2(new_offset + 1); Type new_class_type = cpIndexToType(new_class_index, cp); if (inTryBlock) { processExceptionHandlerTargets(bci, thisUninit); @@ -849,16 +846,16 @@ private BitSet detectFrameOffsets() { var offsets = new BitSet() { @Override public void set(int i) { - if (i < 0 || i >= bytecode.capacity()) throw new IllegalArgumentException(); + Preconditions.checkIndex(i, bytecode.length(), RawBytecodeHelper.IAE_FORMATTER); super.set(i); } }; - RawBytecodeHelper bcs = new RawBytecodeHelper(bytecode); + var bcs = bytecode.start(); boolean no_control_flow = false; int opcode, bci = 0; - while (!bcs.isLastBytecode()) try { - opcode = bcs.rawNext(); - bci = bcs.bci; + while (bcs.next()) try { + opcode = bcs.opcode(); + bci = bcs.bci(); if (no_control_flow) { offsets.set(bci); } @@ -880,20 +877,20 @@ public void set(int i) { } case TABLESWITCH, LOOKUPSWITCH -> { int aligned_bci = RawBytecodeHelper.align(bci + 1); - int default_ofset = bcs.getInt(aligned_bci); + int default_ofset = bcs.getIntUnchecked(aligned_bci); int keys, delta; - if (bcs.rawCode == TABLESWITCH) { - int low = bcs.getInt(aligned_bci + 4); - int high = bcs.getInt(aligned_bci + 2 * 4); + if (bcs.opcode() == TABLESWITCH) { + int low = bcs.getIntUnchecked(aligned_bci + 4); + int high = bcs.getIntUnchecked(aligned_bci + 2 * 4); keys = high - low + 1; delta = 1; } else { - keys = bcs.getInt(aligned_bci + 4); + keys = bcs.getIntUnchecked(aligned_bci + 4); delta = 2; } offsets.set(bci + default_ofset); for (int i = 0; i < keys; i++) { - offsets.set(bci + bcs.getInt(aligned_bci + (3 + i * delta) * 4)); + offsets.set(bci + bcs.getIntUnchecked(aligned_bci + (3 + i * delta) * 4)); } yield true; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 5ee3759bba3..3119cfa0f49 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -849,11 +849,10 @@ public AdHocAttribute(AttributeMapper mapper) { @Override public void writeTo(BufWriterImpl b) { b.writeIndex(b.constantPool().utf8Entry(mapper.name())); - b.writeInt(0); - int start = b.size(); + int lengthIndex = b.skip(4); writeBody(b); - int written = b.size() - start; - b.patchInt(start - 4, 4, written); + int written = b.size() - lengthIndex - 4; + b.patchInt(lengthIndex, written); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 2d9e27b8d74..b0f1de65d92 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -53,9 +53,12 @@ import static java.lang.classfile.ClassFile.ACC_STATIC; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.components.ClassPrinter; -import java.nio.ByteBuffer; import java.util.function.Consumer; +import static jdk.internal.constant.PrimitiveClassDescImpl.CD_double; +import static jdk.internal.constant.PrimitiveClassDescImpl.CD_long; +import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void; + /** * Helper to create and manipulate type descriptors, where type descriptors are * represented as JVM type descriptor strings and symbols are represented as @@ -99,16 +102,18 @@ public void accept(FieldBuilder builder) { private static final int ATTRIBUTE_STABILITY_COUNT = AttributeMapper.AttributeStability.values().length; public static boolean isAttributeAllowed(final Attribute attr, - final ClassFile.AttributesProcessingOption processingOption) { + final ClassFileImpl context) { return attr instanceof BoundAttribute - ? ATTRIBUTE_STABILITY_COUNT - attr.attributeMapper().stability().ordinal() > processingOption.ordinal() + ? ATTRIBUTE_STABILITY_COUNT - attr.attributeMapper().stability().ordinal() > context.attributesProcessingOption().ordinal() : true; } public static int parameterSlots(MethodTypeDesc mDesc) { - int count = 0; - for (int i = 0; i < mDesc.parameterCount(); i++) { - count += slotSize(mDesc.parameterType(i)); + int count = mDesc.parameterCount(); + for (int i = count - 1; i >= 0; i--) { + if (isDoubleSlot(mDesc.parameterType(i))) { + count++; + } } return count; } @@ -118,17 +123,13 @@ public static int[] parseParameterSlots(int flags, MethodTypeDesc mDesc) { int count = ((flags & ACC_STATIC) != 0) ? 0 : 1; for (int i = 0; i < result.length; i++) { result[i] = count; - count += slotSize(mDesc.parameterType(i)); + count += paramSlotSize(mDesc.parameterType(i)); } return result; } public static int maxLocals(int flags, MethodTypeDesc mDesc) { - int count = ((flags & ACC_STATIC) != 0) ? 0 : 1; - for (int i = 0; i < mDesc.parameterCount(); i++) { - count += slotSize(mDesc.parameterType(i)); - } - return count; + return parameterSlots(mDesc) + ((flags & ACC_STATIC) == 0 ? 1 : 0) ; } /** @@ -253,16 +254,15 @@ static void writeList(BufWriterImpl buf, List list) { } public static int slotSize(ClassDesc desc) { - return switch (desc.descriptorString().charAt(0)) { - case 'V' -> 0; - case 'D','J' -> 2; - default -> 1; - }; + return desc == CD_void ? 0 : isDoubleSlot(desc) ? 2 : 1; + } + + public static int paramSlotSize(ClassDesc desc) { + return isDoubleSlot(desc) ? 2 : 1; } public static boolean isDoubleSlot(ClassDesc desc) { - char ch = desc.descriptorString().charAt(0); - return ch == 'D' || ch == 'J'; + return desc == CD_double || desc == CD_long; } public static void dumpMethod(SplitConstantPool cp, @@ -270,7 +270,7 @@ public static void dumpMethod(SplitConstantPool cp, String methodName, MethodTypeDesc methodDesc, int acc, - ByteBuffer bytecode, + RawBytecodeHelper.CodeRange bytecode, Consumer dump) { // try to dump debug info about corrupted bytecode @@ -283,8 +283,8 @@ public static void dumpMethod(SplitConstantPool cp, public void writeBody(BufWriterImpl b) { b.writeU2(-1);//max stack b.writeU2(-1);//max locals - b.writeInt(bytecode.limit()); - b.writeBytes(bytecode.array(), 0, bytecode.limit()); + b.writeInt(bytecode.length()); + b.writeBytes(bytecode.array(), 0, bytecode.length()); b.writeU2(0);//exception handlers b.writeU2(0);//attributes } @@ -292,13 +292,16 @@ public void writeBody(BufWriterImpl b) { ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump); } catch (Error | Exception _) { // fallback to bytecode hex dump - bytecode.rewind(); - while (bytecode.position() < bytecode.limit()) { - dump.accept("%n%04x:".formatted(bytecode.position())); - for (int i = 0; i < 16 && bytecode.position() < bytecode.limit(); i++) { - dump.accept(" %02x".formatted(bytecode.get())); - } + dumpBytesHex(dump, bytecode.array(), bytecode.length()); + } + } + + public static void dumpBytesHex(Consumer dump, byte[] bytes, int length) { + for (int i = 0; i < length; i++) { + if (i % 16 == 0) { + dump.accept("%n%04x:".formatted(i)); } + dump.accept(" %02x".formatted(bytes[i])); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java index c9b076aa1f0..de97730aff5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java @@ -24,9 +24,8 @@ */ package jdk.internal.classfile.impl.verifier; -import java.nio.ByteBuffer; - import java.lang.classfile.ClassFile; + import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType; import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; @@ -83,48 +82,12 @@ static boolean is_valid(int code) { return 0 <= code && code < number_of_codes; } - static int wide_length_for(int code) { - return is_valid(code) ? _lengths[code] >> 4 : -1; - } - static boolean is_store_into_local(int code) { return (ClassFile.ISTORE <= code && code <= ClassFile.ASTORE_3); } static final int _lengths[] = new int[number_of_codes]; - static int special_length_at(int code, byte bytecode[], int bci, int end) { - switch (code) { - case ClassFile.WIDE: - if (bci + 1 >= end) { - return -1; - } - return wide_length_for(bytecode[bci + 1] & 0xff); - case ClassFile.TABLESWITCH: - int aligned_bci = align(bci + 1); - if (aligned_bci + 3 * 4 >= end) { - return -1; - } - ByteBuffer bb = ByteBuffer.wrap(bytecode, aligned_bci + 1 * 4, 2 * 4); - int lo = bb.getInt(); - int hi = bb.getInt(); - int len = aligned_bci - bci + (3 + hi - lo + 1) * 4; - return len > 0 ? len : -1; - case ClassFile.LOOKUPSWITCH: - case _fast_binaryswitch: - case _fast_linearswitch: - aligned_bci = align(bci + 1); - if (aligned_bci + 2 * 4 >= end) { - return -1; - } - int npairs = ByteBuffer.wrap(bytecode, aligned_bci + 4, 4).getInt(); - len = aligned_bci - bci + (2 + 2 * npairs) * 4; - return len > 0 ? len : -1; - default: - return 0; - } - } - static int align(int n) { return (n + 3) & ~3; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java index 74cdb881a74..9a0e781d145 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java @@ -24,7 +24,6 @@ */ package jdk.internal.classfile.impl.verifier; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -316,20 +315,20 @@ void verify_method(VerificationWrapper.MethodWrapper m) { if (code_length < 1 || code_length > MAX_CODE_SIZE) { verifyError(String.format("Invalid method Code length %d", code_length)); } - var code = ByteBuffer.wrap(codeArray, 0, _method.codeLength()); - byte[] code_data = generate_code_data(code, code_length); + var code = RawBytecodeHelper.of(codeArray); + byte[] code_data = generate_code_data(code); int ex_minmax[] = new int[] {code_length, -1}; verify_exception_handler_table(code_length, code_data, ex_minmax); verify_local_variable_table(code_length, code_data); VerificationTable stackmap_table = new VerificationTable(stackmap_data, current_frame, max_locals, max_stack, code_data, code_length, cp, this); - var bcs = new RawBytecodeHelper(code); + var bcs = code.start(); boolean no_control_flow = false; int opcode; - while (!bcs.isLastBytecode()) { - opcode = bcs.rawNext(); - bci = bcs.bci; + while (bcs.next()) { + opcode = bcs.opcode(); + bci = bcs.bci(); current_frame.set_offset(bci); current_frame.set_mark(); stackmap_index = verify_stackmap_table(stackmap_index, bci, current_frame, stackmap_table, no_control_flow); @@ -340,7 +339,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { int target; VerificationType type, type2 = null; VerificationType atype; - if (bcs.isWide) { + if (bcs.isWide()) { if (opcode != ClassFile.IINC && opcode != ClassFile.ILOAD && opcode != ClassFile.ALOAD && opcode != ClassFile.LLOAD && opcode != ClassFile.ISTORE && opcode != ClassFile.ASTORE @@ -1195,7 +1194,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { case ClassFile.MULTIANEWARRAY : { index = bcs.getIndexU2(); - int dim = _method.codeArray()[bcs.bci+3] & 0xff; + int dim = _method.codeArray()[bcs.bci() +3] & 0xff; verify_cp_class_type(bci, index, cp); VerificationType new_array_type = cp_index_to_type(index, cp); @@ -1230,13 +1229,13 @@ void verify_method(VerificationWrapper.MethodWrapper m) { } } - private byte[] generate_code_data(ByteBuffer code, int code_length) { - byte code_data[] = new byte[code_length]; - var bcs = new RawBytecodeHelper(code); - while (!bcs.isLastBytecode()) { - if (bcs.rawNext() != ILLEGAL) { - int bci = bcs.bci; - if (bcs.rawCode == ClassFile.NEW) { + private byte[] generate_code_data(RawBytecodeHelper.CodeRange code) { + byte[] code_data = new byte[code.length()]; + var bcs = code.start(); + while (bcs.next()) { + if (bcs.opcode() != ILLEGAL) { + int bci = bcs.bci(); + if (bcs.opcode() == ClassFile.NEW) { code_data[bci] = NEW_OFFSET; } else { code_data[bci] = BYTECODE_OFFSET; @@ -1410,7 +1409,7 @@ void verify_ldc(int opcode, int index, VerificationFrame current_frame, Constant } void verify_switch(RawBytecodeHelper bcs, int code_length, byte[] code_data, VerificationFrame current_frame, VerificationTable stackmap_table) { - int bci = bcs.bci; + int bci = bcs.bci(); int aligned_bci = VerificationBytecodes.align(bci + 1); // 4639449 & 4647081: padding bytes must be 0 if (_klass.majorVersion() < NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION) { @@ -1422,12 +1421,12 @@ void verify_switch(RawBytecodeHelper bcs, int code_length, byte[] code_data, Ver padding_offset++; } } - int default_ofset = bcs.getInt(aligned_bci); + int default_offset = bcs.getIntUnchecked(aligned_bci); int keys, delta; current_frame.pop_stack(VerificationType.integer_type); - if (bcs.rawCode == ClassFile.TABLESWITCH) { - int low = bcs.getInt(aligned_bci + 4); - int high = bcs.getInt(aligned_bci + 2*4); + if (bcs.opcode() == ClassFile.TABLESWITCH) { + int low = bcs.getIntUnchecked(aligned_bci + 4); + int high = bcs.getIntUnchecked(aligned_bci + 2*4); if (low > high) { verifyError("low must be less than or equal to high in tableswitch"); } @@ -1438,31 +1437,31 @@ void verify_switch(RawBytecodeHelper bcs, int code_length, byte[] code_data, Ver delta = 1; } else { // Make sure that the lookupswitch items are sorted - keys = bcs.getInt(aligned_bci + 4); + keys = bcs.getIntUnchecked(aligned_bci + 4); if (keys < 0) { verifyError("number of keys in lookupswitch less than 0"); } delta = 2; for (int i = 0; i < (keys - 1); i++) { - int this_key = bcs.getInt(aligned_bci + (2+2*i)*4); - int next_key = bcs.getInt(aligned_bci + (2+2*i+2)*4); + int this_key = bcs.getIntUnchecked(aligned_bci + (2+2*i)*4); + int next_key = bcs.getIntUnchecked(aligned_bci + (2+2*i+2)*4); if (this_key >= next_key) { verifyError("Bad lookupswitch instruction"); } } } - int target = bci + default_ofset; + int target = bci + default_offset; stackmap_table.check_jump_target(current_frame, target); for (int i = 0; i < keys; i++) { - aligned_bci = VerificationBytecodes.align(bcs.bci + 1); - target = bci + bcs.getInt(aligned_bci + (3+i*delta)*4); + aligned_bci = VerificationBytecodes.align(bcs.bci() + 1); + target = bci + bcs.getIntUnchecked(aligned_bci + (3+i*delta)*4); stackmap_table.check_jump_target(current_frame, target); } } void verify_field_instructions(RawBytecodeHelper bcs, VerificationFrame current_frame, ConstantPoolWrapper cp, boolean allow_arrays) { int index = bcs.getIndexU2(); - verify_cp_type(bcs.bci, index, cp, 1 << JVM_CONSTANT_Fieldref); + verify_cp_type(bcs.bci(), index, cp, 1 << JVM_CONSTANT_Fieldref); String field_name = cp.refNameAt(index); String field_sig = cp.refSignatureAt(index); if (!VerificationSignature.isValidTypeSignature(field_sig)) verifyError("Invalid field signature"); @@ -1477,7 +1476,7 @@ void verify_field_instructions(RawBytecodeHelper bcs, VerificationFrame current_ VerificationType stack_object_type = null; int n = change_sig_to_verificationType(sig_stream, field_type, 0); boolean is_assignable; - switch (bcs.rawCode) { + switch (bcs.opcode()) { case ClassFile.GETSTATIC -> { for (int i = 0; i < n; i++) { current_frame.push_stack(field_type[i]); @@ -1524,7 +1523,7 @@ boolean ends_in_athrow(int start_bc_offset) { boolean verify_invoke_init(RawBytecodeHelper bcs, int ref_class_index, VerificationType ref_class_type, VerificationFrame current_frame, int code_length, boolean in_try_block, boolean this_uninit, ConstantPoolWrapper cp, VerificationTable stackmap_table) { - int bci = bcs.bci; + int bci = bcs.bci(); VerificationType type = current_frame.pop_stack(VerificationType.reference_check); if (type.is_uninitialized_this(this)) { String superk_name = current_class().superclassName(); @@ -1552,7 +1551,7 @@ boolean verify_invoke_init(RawBytecodeHelper bcs, int ref_class_index, Verificat if (new_offset > (code_length - 3) || (_method.codeArray()[new_offset] & 0xff) != ClassFile.NEW) { verifyError("Expecting new instruction"); } - int new_class_index = bcs.getIndexU2Raw(new_offset + 1); + int new_class_index = bcs.getU2(new_offset + 1); verify_cp_class_type(bci, new_class_index, cp); VerificationType new_class_type = cp_index_to_type( new_class_index, cp); @@ -1583,7 +1582,7 @@ static boolean is_same_or_direct_interface(VerificationWrapper klass, Verificati boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, VerificationFrame current_frame, boolean in_try_block, boolean this_uninit, VerificationType return_type, ConstantPoolWrapper cp, VerificationTable stackmap_table) { // Make sure the constant pool item is the right type int index = bcs.getIndexU2(); - int opcode = bcs.rawCode; + int opcode = bcs.opcode(); int types = 0; switch (opcode) { case ClassFile.INVOKEINTERFACE: @@ -1601,7 +1600,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif default: types = 1 << JVM_CONSTANT_Methodref; } - verify_cp_type(bcs.bci, index, cp, types); + verify_cp_type(bcs.bci(), index, cp, types); String method_name = cp.refNameAt(index); String method_sig = cp.refSignatureAt(index); if (!VerificationSignature.isValidMethodSignature(method_sig)) verifyError("Invalid method signature"); @@ -1619,7 +1618,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif mth_sig_verif_types = new sig_as_verification_types(verif_types); create_method_sig_entry(mth_sig_verif_types, sig); int nargs = mth_sig_verif_types.num_args(); - int bci = bcs.bci; + int bci = bcs.bci(); if (opcode == ClassFile.INVOKEINTERFACE) { if ((_method.codeArray()[bci+3] & 0xff) != (nargs+1)) { verifyError("Inconsistent args count operand in invokeinterface"); diff --git a/src/java.base/share/classes/jdk/internal/event/ThreadSleepEvent.java b/src/java.base/share/classes/jdk/internal/event/ThreadSleepEvent.java index ab9b377c0f3..283ba425977 100644 --- a/src/java.base/share/classes/jdk/internal/event/ThreadSleepEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/ThreadSleepEvent.java @@ -30,14 +30,5 @@ */ public final class ThreadSleepEvent extends Event { - private static final ThreadSleepEvent EVENT = new ThreadSleepEvent(); - - /** - * Returns {@code true} if event is enabled, {@code false} otherwise. - */ - public static boolean isTurnedOn() { - return EVENT.isEnabled(); - } - public long time; } diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 5d43c28a667..83b11b7ce68 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -304,20 +304,25 @@ public boolean isNative() { @Override public final Optional asOverlappingSlice(MemorySegment other) { - AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other); - if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or heap + final AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other); + if (overlaps(that)) { + final long offsetToThat = that.address() - this.address(); + final long newOffset = offsetToThat >= 0 ? offsetToThat : 0; + return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat))); + } + return Optional.empty(); + } + + @ForceInline + private boolean overlaps(AbstractMemorySegmentImpl that) { + if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or the same heap segment final long thisStart = this.unsafeGetOffset(); final long thatStart = that.unsafeGetOffset(); final long thisEnd = thisStart + this.byteSize(); final long thatEnd = thatStart + that.byteSize(); - - if (thisStart < thatEnd && thisEnd > thatStart) { //overlap occurs - long offsetToThat = that.address() - this.address(); - long newOffset = offsetToThat >= 0 ? offsetToThat : 0; - return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat))); - } + return (thisStart < thatEnd && thisEnd > thatStart); //overlap occurs? } - return Optional.empty(); + return false; } @Override @@ -645,6 +650,64 @@ private static Object bufferRef(Buffer buffer) { } } + // COPY_NATIVE_THRESHOLD must be a power of two and should be greater than 2^3 + private static final long COPY_NATIVE_THRESHOLD = 1 << 6; + + @ForceInline + public static void copy(AbstractMemorySegmentImpl src, long srcOffset, + AbstractMemorySegmentImpl dst, long dstOffset, + long size) { + + Utils.checkNonNegativeIndex(size, "size"); + // Implicit null check for src and dst + src.checkAccess(srcOffset, size, true); + dst.checkAccess(dstOffset, size, false); + + if (size <= 0) { + // Do nothing + } else if (size < COPY_NATIVE_THRESHOLD && !src.overlaps(dst)) { + // 0 < size < FILL_NATIVE_LIMIT : 0...0X...XXXX + // + // Strictly, we could check for !src.asSlice(srcOffset, size).overlaps(dst.asSlice(dstOffset, size) but + // this is a bit slower and it likely very unusual there is any difference in the outcome. Also, if there + // is an overlap, we could tolerate one particular direction of overlap (but not the other). + + // 0...0X...X000 + final int limit = (int) (size & (COPY_NATIVE_THRESHOLD - 8)); + int offset = 0; + for (; offset < limit; offset += 8) { + final long v = SCOPED_MEMORY_ACCESS.getLong(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putLong(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + } + int remaining = (int) size - offset; + // 0...0X00 + if (remaining >= 4) { + final int v = SCOPED_MEMORY_ACCESS.getInt(src.sessionImpl(), src.unsafeGetBase(),src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putInt(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + offset += 4; + remaining -= 4; + } + // 0...00X0 + if (remaining >= 2) { + final short v = SCOPED_MEMORY_ACCESS.getShort(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putShort(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + offset += 2; + remaining -=2; + } + // 0...000X + if (remaining == 1) { + final byte v = SCOPED_MEMORY_ACCESS.getByte(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putByte(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + } + // We have now fully handled 0...0X...XXXX + } else { + // For larger sizes, the transition to native code pays off + SCOPED_MEMORY_ACCESS.copyMemory(src.sessionImpl(), dst.sessionImpl(), + src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset, + dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset, size); + } + } + @ForceInline public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset, MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, diff --git a/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java index e313780a348..181a560c5f0 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java @@ -72,23 +72,28 @@ public boolean isMapped() { public void load() { if (unmapper != null) { - SCOPED_MEMORY_ACCESS.load(sessionImpl(), min, unmapper.isSync(), length); + SCOPED_MEMORY_ACCESS.load(sessionImpl(), NIO_ACCESS.mappedMemoryUtils(), + min, unmapper.isSync(), length); } } public void unload() { if (unmapper != null) { - SCOPED_MEMORY_ACCESS.unload(sessionImpl(), min, unmapper.isSync(), length); + SCOPED_MEMORY_ACCESS.unload(sessionImpl(), NIO_ACCESS.mappedMemoryUtils(), + min, unmapper.isSync(), length); } } public boolean isLoaded() { - return unmapper == null || SCOPED_MEMORY_ACCESS.isLoaded(sessionImpl(), min, unmapper.isSync(), length); + return unmapper == null || + SCOPED_MEMORY_ACCESS.isLoaded(sessionImpl(), + NIO_ACCESS.mappedMemoryUtils(), min, unmapper.isSync(), length); } public void force() { if (unmapper != null) { - SCOPED_MEMORY_ACCESS.force(sessionImpl(), unmapper.fileDescriptor(), min, unmapper.isSync(), 0, length); + SCOPED_MEMORY_ACCESS.force(sessionImpl(), NIO_ACCESS.mappedMemoryUtils(), + unmapper.fileDescriptor(), min, unmapper.isSync(), 0, length); } } diff --git a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template index e3f8787e9e6..a1116e1df38 100644 --- a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template +++ b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template @@ -34,6 +34,7 @@ import java.lang.ref.Reference; import java.io.FileDescriptor; import java.util.function.Supplier; +import jdk.internal.access.foreign.MappedMemoryUtilsProxy; import jdk.internal.access.JavaNioAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.foreign.AbstractMemorySegmentImpl; @@ -237,84 +238,84 @@ public class ScopedMemoryAccess { } @ForceInline - public boolean isLoaded(MemorySessionImpl session, long address, boolean isSync, long size) { + public boolean isLoaded(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { - return isLoadedInternal(session, address, isSync, size); + return isLoadedInternal(session, mappedUtils, address, isSync, size); } catch (ScopedAccessError ex) { throw ex.newRuntimeException(); } } @ForceInline @Scoped - public boolean isLoadedInternal(MemorySessionImpl session, long address, boolean isSync, long size) { + public boolean isLoadedInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { if (session != null) { session.checkValidStateRaw(); } - return SharedSecrets.getJavaNioAccess().isLoaded(address, isSync, size); + return mappedUtils.isLoaded(address, isSync, size); } finally { Reference.reachabilityFence(session); } } @ForceInline - public void load(MemorySessionImpl session, long address, boolean isSync, long size) { + public void load(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { - loadInternal(session, address, isSync, size); + loadInternal(session, mappedUtils, address, isSync, size); } catch (ScopedAccessError ex) { throw ex.newRuntimeException(); } } @ForceInline @Scoped - public void loadInternal(MemorySessionImpl session, long address, boolean isSync, long size) { + public void loadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { if (session != null) { session.checkValidStateRaw(); } - SharedSecrets.getJavaNioAccess().load(address, isSync, size); + mappedUtils.load(address, isSync, size); } finally { Reference.reachabilityFence(session); } } @ForceInline - public void unload(MemorySessionImpl session, long address, boolean isSync, long size) { + public void unload(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { - unloadInternal(session, address, isSync, size); + unloadInternal(session, mappedUtils, address, isSync, size); } catch (ScopedAccessError ex) { throw ex.newRuntimeException(); } } @ForceInline @Scoped - public void unloadInternal(MemorySessionImpl session, long address, boolean isSync, long size) { + public void unloadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { if (session != null) { session.checkValidStateRaw(); } - SharedSecrets.getJavaNioAccess().unload(address, isSync, size); + mappedUtils.unload(address, isSync, size); } finally { Reference.reachabilityFence(session); } } @ForceInline - public void force(MemorySessionImpl session, FileDescriptor fd, long address, boolean isSync, long index, long length) { + public void force(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, FileDescriptor fd, long address, boolean isSync, long index, long length) { try { - forceInternal(session, fd, address, isSync, index, length); + forceInternal(session, mappedUtils, fd, address, isSync, index, length); } catch (ScopedAccessError ex) { throw ex.newRuntimeException(); } } @ForceInline @Scoped - public void forceInternal(MemorySessionImpl session, FileDescriptor fd, long address, boolean isSync, long index, long length) { + public void forceInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, FileDescriptor fd, long address, boolean isSync, long index, long length) { try { if (session != null) { session.checkValidStateRaw(); } - SharedSecrets.getJavaNioAccess().force(fd, address, isSync, index, length); + mappedUtils.force(fd, address, isSync, index, length); } finally { Reference.reachabilityFence(session); } diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 110a3e97a33..f412694234f 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -172,6 +172,7 @@ jdk.jartool, jdk.jlink, jdk.jfr, + jdk.management, jdk.net, // SapMachine 2024-06-12: process group extension jdk.sapext, diff --git a/src/java.base/share/classes/sun/security/ec/ed/EdDSAParameters.java b/src/java.base/share/classes/sun/security/ec/ed/EdDSAParameters.java index 6e06a890bbd..ef6720dc033 100644 --- a/src/java.base/share/classes/sun/security/ec/ed/EdDSAParameters.java +++ b/src/java.base/share/classes/sun/security/ec/ed/EdDSAParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package sun.security.ec.ed; import sun.security.ec.ParametersMap; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; import sun.security.util.ObjectIdentifier; import sun.security.util.KnownOIDs; import sun.security.util.math.*; diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java index 23925869b9f..324cc3e7cec 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, 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 @@ -38,7 +38,7 @@ import java.util.function.Function; import sun.security.jca.JCAUtil; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; import sun.security.timestamp.*; import sun.security.util.*; import sun.security.x509.*; diff --git a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java index ed075354a16..699e68d053c 100644 --- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java +++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java @@ -32,7 +32,7 @@ import java.security.spec.PSSParameterSpec; import java.util.*; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; import sun.security.timestamp.TimestampToken; import sun.security.util.*; import sun.security.x509.AlgorithmId; diff --git a/src/java.base/share/classes/sun/security/provider/SHA3.java b/src/java.base/share/classes/sun/security/provider/SHA3.java index eaccf2a88e9..75430c63916 100644 --- a/src/java.base/share/classes/sun/security/provider/SHA3.java +++ b/src/java.base/share/classes/sun/security/provider/SHA3.java @@ -34,6 +34,8 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; +import static java.lang.Math.min; + /** * This class implements the Secure Hash Algorithm SHA-3 developed by * the National Institute of Standards and Technology along with the @@ -46,7 +48,7 @@ * @since 9 * @author Valerie Peng */ -abstract class SHA3 extends DigestBase { +public abstract class SHA3 extends DigestBase { private static final int WIDTH = 200; // in bytes, e.g. 1600 bits private static final int DM = 5; // dimension of state matrix @@ -65,9 +67,24 @@ abstract class SHA3 extends DigestBase { 0x8000000000008080L, 0x80000001L, 0x8000000080008008L, }; + // The starting byte combining the 2 or 4-bit domain separator and + // leading bits of the 10*1 padding, see Table 6 in B.2 of FIPS PUB 202 + // for examples private final byte suffix; + + // the state matrix flattened into an array private long[] state = new long[DM*DM]; + // The byte offset in the state where the next squeeze() will start. + // -1 indicates that either we are in the absorbing phase (only + // update() calls were made so far) in an extendable-output function (XOF) + // or the class was initialized as a hash. + // The first squeeze() call (after a possibly empty sequence of update() + // calls) will set it to 0 at its start. + // When a squeeze() call uses up all available bytes from this state + // and so a new keccak() call is made, squeezeOffset is reset to 0. + protected int squeezeOffset = -1; + static final VarHandle asLittleEndian = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN).withInvokeExactBehavior(); @@ -75,7 +92,7 @@ abstract class SHA3 extends DigestBase { /** * Creates a new SHA-3 object. */ - SHA3(String name, int digestLength, byte suffix, int c) { + private SHA3(String name, int digestLength, byte suffix, int c) { super(name, digestLength, (WIDTH - c)); this.suffix = suffix; } @@ -103,54 +120,141 @@ private void implCompress0(byte[] b, int ofs) { keccak(); } + void finishAbsorb() { + int numOfPadding = + setPaddingBytes(suffix, buffer, (int)(bytesProcessed % blockSize)); + if (numOfPadding < 1) { + throw new ProviderException("Incorrect pad size: " + numOfPadding); + } + implCompress(buffer, 0); + } + /** * Return the digest. Subclasses do not need to reset() themselves, * DigestBase calls implReset() when necessary. */ void implDigest(byte[] out, int ofs) { + // Moving this allocation to the block where it is used causes a little + // performance drop, that is why it is here. byte[] byteState = new byte[8]; - int numOfPadding = - setPaddingBytes(suffix, buffer, (int)(bytesProcessed % blockSize)); - if (numOfPadding < 1) { - throw new ProviderException("Incorrect pad size: " + numOfPadding); + if (engineGetDigestLength() == 0) { + // This is an XOF, so the digest() call is illegal. + throw new ProviderException("Calling digest() is not allowed in an XOF"); } - implCompress(buffer, 0); - int availableBytes = blockSize; // i.e. buffer.length + + finishAbsorb(); + + int availableBytes = blockSize; int numBytes = engineGetDigestLength(); + while (numBytes > availableBytes) { - for (int i = 0; i < availableBytes / 8 ; i++) { + for (int i = 0; i < availableBytes / 8; i++) { asLittleEndian.set(out, ofs, state[i]); ofs += 8; } numBytes -= availableBytes; keccak(); } - int numLongs = (numBytes + 7) / 8; + int numLongs = numBytes / 8; - for (int i = 0; i < numLongs - 1; i++) { + for (int i = 0; i < numLongs; i++) { asLittleEndian.set(out, ofs, state[i]); ofs += 8; } - if (numBytes == numLongs * 8) { - asLittleEndian.set(out, ofs, state[numLongs - 1]); - } else { - asLittleEndian.set(byteState, 0, state[numLongs - 1]); - System.arraycopy(byteState, 0, - out, ofs, numBytes - (numLongs - 1) * 8); + if (numBytes % 8 != 0) { + asLittleEndian.set(byteState, 0, state[numLongs]); + System.arraycopy(byteState, 0, out, ofs, numBytes % 8); } } + void implSqueeze(byte[] output, int offset, int numBytes) { + // Moving this allocation to the block where it is used causes a little + // performance drop, that is why it is here. + byte[] byteState = new byte[8]; + if (engineGetDigestLength() != 0) { + // This is not an XOF, so the squeeze() call is illegal. + throw new ProviderException("Squeezing is only allowed in XOF mode."); + } + + if (squeezeOffset == -1) { + finishAbsorb(); + squeezeOffset = 0; + } + + int availableBytes = blockSize - squeezeOffset; + + while (numBytes > availableBytes) { + int longOffset = squeezeOffset / 8; + int bytesToCopy = 0; + + if (longOffset * 8 < squeezeOffset) { + asLittleEndian.set(byteState, 0, state[longOffset]); + longOffset++; + bytesToCopy = longOffset * 8 - squeezeOffset; + System.arraycopy(byteState, 8 - bytesToCopy, + output, offset, bytesToCopy); + offset += bytesToCopy; + } + for (int i = longOffset; i < blockSize / 8; i++) { + asLittleEndian.set(output, offset, state[i]); + offset += 8; + } + keccak(); + squeezeOffset = 0; + numBytes -= availableBytes; + availableBytes = blockSize; + } + // now numBytes <= availableBytes + int longOffset = squeezeOffset / 8; + + if (longOffset * 8 < squeezeOffset) { + asLittleEndian.set(byteState, 0, state[longOffset]); + int bytesToCopy = min((longOffset + 1) * 8 - squeezeOffset, numBytes); + System.arraycopy(byteState, squeezeOffset - 8 * longOffset, + output, offset, bytesToCopy); + longOffset++; + numBytes -= bytesToCopy; + offset += bytesToCopy; + squeezeOffset += bytesToCopy; + + if (numBytes == 0) return; + } + + int numLongs = numBytes / 8; + + for (int i = longOffset; i < longOffset + numLongs; i++) { + asLittleEndian.set(output, offset, state[i]); + offset += 8; + numBytes -= 8; + squeezeOffset += 8; + } + + if (numBytes > 0) { + asLittleEndian.set(byteState, 0, state[squeezeOffset / 8]); + System.arraycopy(byteState, 0, output, offset, numBytes); + squeezeOffset += numBytes; + } + } + + byte[] implSqueeze(int numBytes) { + byte[] result = new byte[numBytes]; + implSqueeze(result, 0, numBytes); + return result; + } + /** * Resets the internal state to start a new hash. */ void implReset() { Arrays.fill(state, 0L); + squeezeOffset = -1; } /** * Utility function for padding the specified data based on the - * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" required - * for SHA-3 hash (section 6.1). + * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" or 4-bit + * suffix "1111" required for SHA-3 hash functions (section 6.1) and + * extendable-output functions (section 6.1) respectively. */ private static int setPaddingBytes(byte suffix, byte[] in, int len) { if (len != in.length) { @@ -169,16 +273,20 @@ private static int setPaddingBytes(byte suffix, byte[] in, int len) { * rate r = 1600 and capacity c. */ private void keccak() { + keccak(state); + } + + public static void keccak(long[] stateArr) { long a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; long a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24; // move data into local variables - a0 = state[0]; a1 = state[1]; a2 = state[2]; a3 = state[3]; a4 = state[4]; - a5 = state[5]; a6 = state[6]; a7 = state[7]; a8 = state[8]; a9 = state[9]; - a10 = state[10]; a11 = state[11]; a12 = state[12]; a13 = state[13]; a14 = state[14]; - a15 = state[15]; a16 = state[16]; a17 = state[17]; a18 = state[18]; a19 = state[19]; - a20 = state[20]; a21 = state[21]; a22 = state[22]; a23 = state[23]; a24 = state[24]; + a0 = stateArr[0]; a1 = stateArr[1]; a2 = stateArr[2]; a3 = stateArr[3]; a4 = stateArr[4]; + a5 = stateArr[5]; a6 = stateArr[6]; a7 = stateArr[7]; a8 = stateArr[8]; a9 = stateArr[9]; + a10 = stateArr[10]; a11 = stateArr[11]; a12 = stateArr[12]; a13 = stateArr[13]; a14 = stateArr[14]; + a15 = stateArr[15]; a16 = stateArr[16]; a17 = stateArr[17]; a18 = stateArr[18]; a19 = stateArr[19]; + a20 = stateArr[20]; a21 = stateArr[21]; a22 = stateArr[22]; a23 = stateArr[23]; a24 = stateArr[24]; - // process the lanes through step mappings + // process the stateArr through step mappings for (int ir = 0; ir < NR; ir++) { // Step mapping Theta as defined in section 3.2.1. long c0 = a0^a5^a10^a15^a20; @@ -280,11 +388,11 @@ private void keccak() { a0 ^= RC_CONSTANTS[ir]; } - state[0] = a0; state[1] = a1; state[2] = a2; state[3] = a3; state[4] = a4; - state[5] = a5; state[6] = a6; state[7] = a7; state[8] = a8; state[9] = a9; - state[10] = a10; state[11] = a11; state[12] = a12; state[13] = a13; state[14] = a14; - state[15] = a15; state[16] = a16; state[17] = a17; state[18] = a18; state[19] = a19; - state[20] = a20; state[21] = a21; state[22] = a22; state[23] = a23; state[24] = a24; + stateArr[0] = a0; stateArr[1] = a1; stateArr[2] = a2; stateArr[3] = a3; stateArr[4] = a4; + stateArr[5] = a5; stateArr[6] = a6; stateArr[7] = a7; stateArr[8] = a8; stateArr[9] = a9; + stateArr[10] = a10; stateArr[11] = a11; stateArr[12] = a12; stateArr[13] = a13; stateArr[14] = a14; + stateArr[15] = a15; stateArr[16] = a16; stateArr[17] = a17; stateArr[18] = a18; stateArr[19] = a19; + stateArr[20] = a20; stateArr[21] = a21; stateArr[22] = a22; stateArr[23] = a23; stateArr[24] = a24; } public Object clone() throws CloneNotSupportedException { @@ -328,4 +436,85 @@ public SHA512() { super("SHA3-512", 64, (byte)0x06, 128); } } + + public abstract static class SHA3XOF extends SHA3 { + public SHA3XOF(String name, int digestLength, byte offset, int c) { + super(name, digestLength, offset, c); + } + public void update(byte in) { + if (squeezeOffset != -1) { + throw new ProviderException("update() after squeeze() is not allowed."); + } + engineUpdate(in); + } + public void update(byte[] in, int off, int len) { + if (squeezeOffset != -1) { + throw new ProviderException("update() after squeeze() is not allowed."); + } + engineUpdate(in, off, len); + } + + public void update(byte[] in) { + if (squeezeOffset != -1) { + throw new ProviderException("update() after squeeze() is not allowed."); + } + engineUpdate(in, 0, in.length); + } + + public byte[] digest() { + return engineDigest(); + } + + public void squeeze(byte[] output, int offset, int numBytes) { + implSqueeze(output, offset, numBytes); + } + public byte[] squeeze(int numBytes) { + return implSqueeze(numBytes); + } + + public void reset() { + engineReset(); + } + } + + /* + * The SHAKE128 extendable output function. + */ + public static final class SHAKE128 extends SHA3XOF { + // d is the required number of output bytes. + // If this constructor is used with d > 0, the squeezing methods + // will throw a ProviderException. + public SHAKE128(int d) { + super("SHAKE128", d, (byte) 0x1F, 32); + } + + // If this constructor is used to get an instance of the class, then, + // after the last update, one can get the generated bytes using the + // squeezing methods. + // Calling digest method will throw a ProviderException. + public SHAKE128() { + super("SHAKE128", 0, (byte) 0x1F, 32); + } + } + + /* + * The SHAKE256 extendable output function. + */ + public static final class SHAKE256 extends SHA3XOF { + // d is the required number of output bytes. + // If this constructor is used with d > 0, the squeezing methods will + // throw a ProviderException. + public SHAKE256(int d) { + super("SHAKE256", d, (byte) 0x1F, 64); + } + + // If this constructor is used to get an instance of the class, then, + // after the last update, one can get the generated bytes using the + // squeezing methods. + // Calling a digest method will throw a ProviderException. + public SHAKE256() { + super("SHAKE256", 0, (byte) 0x1F, 64); + } + } + } diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index b2527a7fc2c..00e40c5f587 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -1789,7 +1789,8 @@ private char[] promptForKeyPass(String alias, String orig, char[] origPass) thro */ private char[] promptForCredential() throws Exception { // Handle password supplied via stdin - if (System.console() == null) { + Console console = System.console(); + if (console == null || !console.isTerminal()) { char[] importPass = Password.readPassword(System.in); passwords.add(importPass); return importPass; diff --git a/src/java.base/share/classes/sun/security/util/Cache.java b/src/java.base/share/classes/sun/security/util/Cache.java index 3d8350c1ecd..a8449f0fc27 100644 --- a/src/java.base/share/classes/sun/security/util/Cache.java +++ b/src/java.base/share/classes/sun/security/util/Cache.java @@ -59,7 +59,7 @@ * However, note that because of the way SoftReferences are implemented in * HotSpot at the moment, this may not work perfectly as it clears them fairly * eagerly. Performance may be improved if the Java heap size is set to larger - * value using e.g. java -ms64M -mx128M foo.Test + * value using e.g. java -Xms64M -Xmx128M foo.Test * * Cache sizing: the memory cache is implemented on top of a LinkedHashMap. * In its current implementation, the number of buckets (NOT entries) in diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 5896a073043..58e4faf17c3 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -4825,7 +4825,7 @@ level to a file called \f[V]gc.txt\f[R] with no decorations. The default configuration for all other messages at level \f[V]warning\f[R] is still in effect. .TP -\f[V]-Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1024\f[R] +\f[V]-Xlog:gc=trace:file=gctrace.txt:uptimemillis,pid:filecount=5,filesize=1024\f[R] Logs messages tagged with the \f[V]gc\f[R] tag using the \f[V]trace\f[R] level to a rotating file set with 5 files with size 1 MB with the base name \f[V]gctrace.txt\f[R] and uses decorations \f[V]uptimemillis\f[R] diff --git a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c index acc7f0c73c9..c8c948e7767 100644 --- a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c +++ b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c @@ -528,7 +528,7 @@ jint unix_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, * position integer as a filename. */ if ((dir = opendir("/proc")) == NULL) { - JNU_ThrowByNameWithLastError(env, + JNU_ThrowByNameWithMessageAndLastError(env, "java/lang/RuntimeException", "Unable to open /proc"); return -1; } diff --git a/src/java.base/unix/native/libjsig/jsig.c b/src/java.base/unix/native/libjsig/jsig.c index 1a0a6bec892..180dd583393 100644 --- a/src/java.base/unix/native/libjsig/jsig.c +++ b/src/java.base/unix/native/libjsig/jsig.c @@ -42,14 +42,7 @@ #include #include #include - -#if (__STDC_VERSION__ >= 199901L) - #include -#else - #define bool int - #define true 1 - #define false 0 -#endif +#include #define MAX_SIGNALS NSIG diff --git a/src/java.base/unix/native/libnio/MappedMemoryUtils.c b/src/java.base/unix/native/libnio/MappedMemoryUtils.c index cdd8edff22a..6cfa3b47f84 100644 --- a/src/java.base/unix/native/libnio/MappedMemoryUtils.c +++ b/src/java.base/unix/native/libnio/MappedMemoryUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -40,9 +40,8 @@ typedef unsigned char mincore_vec_t; typedef char mincore_vec_t; #endif -JNIEXPORT jboolean JNICALL -Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, - jlong len, jlong numPages) +jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) { jboolean loaded = JNI_TRUE; int result = 0; @@ -80,8 +79,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, +void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, jlong len) { char *a = (char *)jlong_to_ptr(address); @@ -91,9 +89,8 @@ Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, } } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, - jlong len) +void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, + jlong len) { char *a = (char *)jlong_to_ptr(address); int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED); @@ -102,8 +99,7 @@ Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, } } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, +void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, jlong address, jlong len) { void* a = (void *)jlong_to_ptr(address); @@ -112,3 +108,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed"); } } + +#define FD "Ljava/io/FileDescriptor;" + +static JNINativeMethod methods[] = { + {"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0}, + {"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0}, + {"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0}, + {"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0}, +}; + +JNIEXPORT void JNICALL +Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls) +{ + (*env)->RegisterNatives(env, cls, + methods, sizeof(methods)/sizeof(methods[0])); +} diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java index cf58d980bbe..10e02b4ba72 100644 --- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -490,12 +490,26 @@ public String canonicalize(String path) throws IOException { return path; return "" + ((char) (c-32)) + ':' + '\\'; } - return canonicalize0(path); + String canonicalPath = canonicalize0(path); + String finalPath = null; + try { + finalPath = getFinalPath(canonicalPath); + } catch (IOException ignored) { + finalPath = canonicalPath; + } + return finalPath; } private native String canonicalize0(String path) throws IOException; + private String getFinalPath(String path) throws IOException { + return getFinalPath0(path); + } + + private native String getFinalPath0(String path) + throws IOException; + /* -- Attribute accessors -- */ diff --git a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c index 43ce9216271..2598eaa6fec 100644 --- a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c +++ b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -46,31 +46,15 @@ static struct { jfieldID path; } ids; -/** - * GetFinalPathNameByHandle is available on Windows Vista and newer - */ -typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); -static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; - JNIEXPORT void JNICALL Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls) { - HMODULE handle; jclass fileClass; fileClass = (*env)->FindClass(env, "java/io/File"); CHECK_NULL(fileClass); ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;"); CHECK_NULL(ids.path); - - // GetFinalPathNameByHandle requires Windows Vista or newer - if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), - (LPCWSTR)&CreateFileW, &handle) != 0) - { - GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc) - GetProcAddress(handle, "GetFinalPathNameByHandleW"); - } } /* -- Path operations -- */ @@ -88,10 +72,6 @@ static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path) WCHAR *result; DWORD error; - /* Need Windows Vista or newer to get the final path */ - if (GetFinalPathNameByHandle_func == NULL) - return NULL; - h = CreateFileW(path, FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | @@ -109,13 +89,13 @@ static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path) */ result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR)); if (result != NULL) { - DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0); + DWORD len = GetFinalPathNameByHandleW(h, result, MAX_PATH, 0); if (len >= MAX_PATH) { /* retry with a buffer of the right size */ WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR)); if (newResult != NULL) { result = newResult; - len = (*GetFinalPathNameByHandle_func)(h, result, len, 0); + len = GetFinalPathNameByHandleW(h, result, len, 0); } else { len = 0; JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); @@ -351,6 +331,25 @@ Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this, return rv; } +JNIEXPORT jstring JNICALL +Java_java_io_WinNTFileSystem_getFinalPath0(JNIEnv* env, jobject this, jstring pathname) { + jstring rv = NULL; + + WITH_UNICODE_STRING(env, pathname, path) { + WCHAR* finalPath = getFinalPath(env, path); + if (finalPath != NULL) { + rv = (*env)->NewString(env, finalPath, (jsize)wcslen(finalPath)); + free(finalPath); + } + } END_UNICODE_STRING(env, path); + + if (rv == NULL && !(*env)->ExceptionCheck(env)) { + JNU_ThrowIOExceptionWithLastError(env, "Bad pathname"); + } + + return rv; +} + /* -- Attribute accessors -- */ /* Check whether or not the file name in "path" is a Windows reserved diff --git a/src/java.base/windows/native/libnio/MappedMemoryUtils.c b/src/java.base/windows/native/libnio/MappedMemoryUtils.c index 5017ca63a92..6e43dfb505f 100644 --- a/src/java.base/windows/native/libnio/MappedMemoryUtils.c +++ b/src/java.base/windows/native/libnio/MappedMemoryUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -30,9 +30,8 @@ #include "java_nio_MappedMemoryUtils.h" #include -JNIEXPORT jboolean JNICALL -Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, - jlong len, jlong numPages) +jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) { jboolean loaded = JNI_FALSE; /* Information not available? @@ -43,22 +42,19 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres return loaded; } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, +void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, jlong len) { // no madvise available } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, - jlong len) +void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, + jlong len) { // no madvise available } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, +void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, jlong address, jlong len) { void *a = (void *) jlong_to_ptr(address); @@ -106,3 +102,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, JNU_ThrowIOExceptionWithLastError(env, "Flush failed"); } } + +#define FD "Ljava/io/FileDescriptor;" + +static JNINativeMethod methods[] = { + {"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0}, + {"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0}, + {"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0}, + {"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0}, +}; + +JNIEXPORT void JNICALL +Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls) +{ + (*env)->RegisterNatives(env, cls, + methods, sizeof(methods)/sizeof(methods[0])); +} diff --git a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java index 7f8cee373f7..138f093be2f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -95,7 +95,7 @@ public enum NestingKind { /** * A named class or interface declared within a construct other * than a class or interface. - * @jls 14.3 Local Class Declarations + * @jls 14.3 Local Class and Interface Declarations */ LOCAL, @@ -111,7 +111,7 @@ public enum NestingKind { * More specifically, an inner type element is any nested type element that * is not {@linkplain Modifier#STATIC static}. * @return whether or not the constant is nested - * @jls 14.3 Local Class Declarations + * @jls 14.3 Local Class and Interface Declarations */ public boolean isNested() { return this != TOP_LEVEL; diff --git a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java index 4bb7444cb39..56edb89d3e3 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,15 @@ * The interfaces in this package do not model the structure of a * program inside a method body; for example there is no * representation of a {@code for} loop or {@code try}-{@code finally} - * block. However, the interfaces can model some structures only - * appearing inside method bodies, such as local variables and - * anonymous classes. + * block. Concretely, there is no model of any abstract syntax tree + * (AST) structure of a Java program. However, the interfaces can + * model some structures only appearing inside method bodies, such as + * {@linkplain ElementKind#LOCAL_VARIABLE local variables}, + * {@linkplain NestingKind#ANONYMOUS anonymous classes}, and + * {@linkplain ElementKind#EXCEPTION_PARAMETER exception parameters}. + * Therefore, these interfaces can be used by an AST API to model the + * declarations found in the method bodies of Java compilation units + * (JLS {@jls 7.3}). * *

      When used in the context of annotation * processing, an accurate model of the element being represented must diff --git a/src/java.compiler/share/classes/javax/lang/model/type/NullType.java b/src/java.compiler/share/classes/javax/lang/model/type/NullType.java index 92feb514aab..3b82269b55a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/NullType.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/NullType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -30,7 +30,7 @@ * Represents the null type. * This is the type of the expression {@code null}. * - * @jls 3.10.7 The Null Literal + * @jls 3.10.8 The Null Literal * @jls 4.1 The Kinds of Types and Values * @see javax.lang.model.util.Types#getNullType() * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java index abea88fb6f2..0cac48775f5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java @@ -71,7 +71,7 @@ public interface TypeVariable extends ReferenceType { * non-trivial lower bound. Type variables otherwise have a * lower bound of {@link NullType}. * - * @jls 18.1.3. Bounds + * @jls 18.1.3 Bounds */ TypeMirror getLowerBound(); } diff --git a/src/java.desktop/share/classes/javax/swing/text/html/default.css b/src/java.desktop/share/classes/javax/swing/text/html/default.css index eb37a12b6d8..32f54231f46 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/default.css +++ b/src/java.desktop/share/classes/javax/swing/text/html/default.css @@ -102,7 +102,7 @@ dd {margin-left-ltr: 40; margin-bottom: 0} dd p {margin-left: 0; - margin-rigth: 0; + margin-right: 0; margin-top: 0; margin-bottom: 0} diff --git a/src/java.management/share/classes/javax/management/ClassAttributeValueExp.java b/src/java.management/share/classes/javax/management/ClassAttributeValueExp.java index 06c488f90fa..f7c40691e39 100644 --- a/src/java.management/share/classes/javax/management/ClassAttributeValueExp.java +++ b/src/java.management/share/classes/javax/management/ClassAttributeValueExp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,37 +39,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID is not constant class ClassAttributeValueExp extends AttributeValueExp { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -2212731951078526753L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -1081892073854801359L; - - private static final long serialVersionUID; - static { - boolean compat = false; - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: exception means no compat with 1.0, too bad - } - if (compat) - serialVersionUID = oldSerialVersionUID; - else - serialVersionUID = newSerialVersionUID; - } + private static final long serialVersionUID = -1081892073854801359L; /** * @serial The name of the attribute diff --git a/src/java.management/share/classes/javax/management/MBeanAttributeInfo.java b/src/java.management/share/classes/javax/management/MBeanAttributeInfo.java index 6d31becbb73..6551e9ba81b 100644 --- a/src/java.management/share/classes/javax/management/MBeanAttributeInfo.java +++ b/src/java.management/share/classes/javax/management/MBeanAttributeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -40,33 +40,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable { - /* Serial version */ - private static final long serialVersionUID; - static { - /* For complicated reasons, the serialVersionUID changed - between JMX 1.0 and JMX 1.1, even though JMX 1.1 did not - have compatibility code for this class. So the - serialization produced by this class with JMX 1.2 and - jmx.serial.form=1.0 is not the same as that produced by - this class with JMX 1.1 and jmx.serial.form=1.0. However, - the serialization without that property is the same, and - that is the only form required by JMX 1.2. - */ - long uid = 8644704819898565848L; - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - if ("1.0".equals(form)) - uid = 7043855487133450673L; - } catch (Exception e) { - // OK: exception means no compat with 1.0, too bad - } - serialVersionUID = uid; - } + private static final long serialVersionUID = 8644704819898565848L; static final MBeanAttributeInfo[] NO_ATTRIBUTES = new MBeanAttributeInfo[0]; diff --git a/src/java.management/share/classes/javax/management/Notification.java b/src/java.management/share/classes/javax/management/Notification.java index 9455264fa04..80cf4b464d2 100644 --- a/src/java.management/share/classes/javax/management/Notification.java +++ b/src/java.management/share/classes/javax/management/Notification.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -53,46 +53,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID is not constant public class Notification extends EventObject { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 1716977971058914352L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -7516092053498031989L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("message", String.class), - new ObjectStreamField("sequenceNumber", Long.TYPE), - new ObjectStreamField("source", Object.class), - new ObjectStreamField("sourceObjectName", ObjectName.class), - new ObjectStreamField("timeStamp", Long.TYPE), - new ObjectStreamField("type", String.class), - new ObjectStreamField("userData", Object.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("message", String.class), - new ObjectStreamField("sequenceNumber", Long.TYPE), - new ObjectStreamField("source", Object.class), - new ObjectStreamField("timeStamp", Long.TYPE), - new ObjectStreamField("type", String.class), - new ObjectStreamField("userData", Object.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = -7516092053498031989L; /** * @serialField type String The notification type. * A string expressed in a dot notation similar to Java properties. @@ -108,28 +71,15 @@ public class Notification extends EventObject { * @serialField message String The notification message. * @serialField source Object The object on which the notification initially occurred. */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: exception means no compat with 1.0, too bad - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff - + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("message", String.class), + new ObjectStreamField("sequenceNumber", Long.TYPE), + new ObjectStreamField("source", Object.class), + new ObjectStreamField("timeStamp", Long.TYPE), + new ObjectStreamField("type", String.class), + new ObjectStreamField("userData", Object.class) + }; /** * @serial The notification type. * A string expressed in a dot notation similar to Java properties. @@ -378,21 +328,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("type", type); - fields.put("sequenceNumber", sequenceNumber); - fields.put("timeStamp", timeStamp); - fields.put("userData", userData); - fields.put("message", message); - fields.put("source", source); - out.writeFields(); - } else { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/NumericValueExp.java b/src/java.management/share/classes/javax/management/NumericValueExp.java index 959375a2f50..bae84019d2e 100644 --- a/src/java.management/share/classes/javax/management/NumericValueExp.java +++ b/src/java.management/share/classes/javax/management/NumericValueExp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -45,68 +45,19 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant class NumericValueExp extends QueryEval implements ValueExp { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -6227876276058904000L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -4679739485102359104L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("longVal", Long.TYPE), - new ObjectStreamField("doubleVal", Double.TYPE), - new ObjectStreamField("valIsLong", Boolean.TYPE) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("val", Number.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; - + private static final long serialVersionUID = -4679739485102359104L; /** * @serialField val Number The numeric value * *

      The serialVersionUID of this class is -4679739485102359104L. */ - private static final ObjectStreamField[] serialPersistentFields; + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("val", Number.class) + }; private Number val = 0.0; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: exception means no compat with 1.0, too bad - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff - - /** * Basic constructor. */ @@ -189,44 +140,7 @@ public ValueExp apply(ObjectName name) */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - double doubleVal; - long longVal; - boolean isLong; - ObjectInputStream.GetField fields = in.readFields(); - doubleVal = fields.get("doubleVal", (double)0); - if (fields.defaulted("doubleVal")) - { - throw new NullPointerException("doubleVal"); - } - longVal = fields.get("longVal", (long)0); - if (fields.defaulted("longVal")) - { - throw new NullPointerException("longVal"); - } - isLong = fields.get("valIsLong", false); - if (fields.defaulted("valIsLong")) - { - throw new NullPointerException("valIsLong"); - } - if (isLong) - { - this.val = longVal; - } - else - { - this.val = doubleVal; - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -235,22 +149,7 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("doubleVal", doubleValue()); - fields.put("longVal", longValue()); - fields.put("valIsLong", isLong()); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } @Deprecated diff --git a/src/java.management/share/classes/javax/management/ObjectName.java b/src/java.management/share/classes/javax/management/ObjectName.java index 00d5cc6930d..f20750c9d8a 100644 --- a/src/java.management/share/classes/javax/management/ObjectName.java +++ b/src/java.management/share/classes/javax/management/ObjectName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -222,7 +222,6 @@ * @implNote The maximum allowed length of the domain name in this implementation * is {@code Integer.MAX_VALUE/4} */ -@SuppressWarnings("serial") // don't complain serialVersionUID not constant public class ObjectName implements Comparable, QueryExp { private static final int DOMAIN_PATTERN = 0x8000_0000; private static final int PROPLIST_PATTERN = 0x4000_0000; @@ -294,57 +293,7 @@ private static class PatternProperty extends Property { // Private fields ----------------------------------------> - // Serialization compatibility stuff --------------------> - - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -5467795090068647408L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 1081892073854801359L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("domain", String.class), - new ObjectStreamField("propertyList", Hashtable.class), - new ObjectStreamField("propertyListString", String.class), - new ObjectStreamField("canonicalName", String.class), - new ObjectStreamField("pattern", Boolean.TYPE), - new ObjectStreamField("propertyPattern", Boolean.TYPE) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = { }; - // - // Actual serial version and serial form - private static final long serialVersionUID; - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: exception means no compat with 1.0, too bad - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - - // - // Serialization compatibility stuff <============================== + private static final long serialVersionUID = 1081892073854801359L; // Class private fields -----------------------------------> @@ -1088,90 +1037,32 @@ private void setDomainLength(int length) throws MalformedObjectNameException { /** * Deserializes an {@link ObjectName} from an {@link ObjectInputStream}. - * @serialData

        - *
      • In the current serial form (value of property - * jmx.serial.form differs from - * 1.0): the string - * "<domain>:<properties><wild>", - * where:
          - *
        • <domain> represents the domain part - * of the {@link ObjectName}
        • - *
        • <properties> represents the list of - * properties, as returned by - * {@link #getKeyPropertyListString} - *
        • <wild> is empty if not - * isPropertyPattern, or - * is the character "*" if - * isPropertyPattern - * and <properties> is empty, or - * is ",*" if - * isPropertyPattern and - * <properties> is not empty. - *
        • - *
        - * The intent is that this string could be supplied - * to the {@link #ObjectName(String)} constructor to - * produce an equivalent {@link ObjectName}. - *
      • - *
      • In the old serial form (value of property - * jmx.serial.form is - * 1.0): <domain> <propertyList> - * <propertyListString> <canonicalName> - * <pattern> <propertyPattern>, - * where:
          - *
        • <domain> represents the domain part - * of the {@link ObjectName}
        • - *
        • <propertyList> is the - * {@link Hashtable} that contains all the - * pairs (key,value) for this - * {@link ObjectName}
        • - *
        • <propertyListString> is the - * {@link String} representation of the - * list of properties in any order (not - * mandatorily a canonical representation) - *
        • - *
        • <canonicalName> is the - * {@link String} containing this - * {@link ObjectName}'s canonical name
        • - *
        • <pattern> is a boolean which is - * true if this - * {@link ObjectName} contains a pattern
        • - *
        • <propertyPattern> is a boolean which - * is true if this - * {@link ObjectName} contains a pattern in - * the list of properties
        • - *
        - *
      • + * @serialData The string "<domain>:<properties><wild>", where: + *
          + *
        • <domain> represents the domain part + * of the {@link ObjectName}
        • + *
        • <properties> represents the list of + * properties, as returned by + * {@link #getKeyPropertyListString}
        • + *
        • <wild> is empty if not + * isPropertyPattern, or + * is the character "*" if + * isPropertyPattern + * and <properties> is empty, or + * is ",*" if + * isPropertyPattern and + * <properties> is not empty.
        • *
        + * The intent is that this string could be supplied + * to the {@link #ObjectName(String)} constructor to + * produce an equivalent {@link ObjectName}. */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { String cn; - if (compat) { - // Read an object serialized in the old serial form - // - //in.defaultReadObject(); - final ObjectInputStream.GetField fields = in.readFields(); - String propListString = - (String)fields.get("propertyListString", ""); - - // 6616825: take care of property patterns - final boolean propPattern = - fields.get("propertyPattern" , false); - if (propPattern) { - propListString = - (propListString.length()==0?"*":(propListString+",*")); - } - - cn = (String)fields.get("domain", "default")+ - ":"+ propListString; - } else { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - cn = (String)in.readObject(); - } + in.defaultReadObject(); + cn = (String)in.readObject(); try { construct(cn); @@ -1183,85 +1074,31 @@ private void readObject(ObjectInputStream in) /** * Serializes an {@link ObjectName} to an {@link ObjectOutputStream}. - * @serialData
          - *
        • In the current serial form (value of property - * jmx.serial.form differs from - * 1.0): the string - * "<domain>:<properties><wild>", - * where:
            - *
          • <domain> represents the domain part - * of the {@link ObjectName}
          • - *
          • <properties> represents the list of - * properties, as returned by - * {@link #getKeyPropertyListString} - *
          • <wild> is empty if not - * isPropertyPattern, or - * is the character "*" if - * this isPropertyPattern - * and <properties> is empty, or - * is ",*" if - * isPropertyPattern and - * <properties> is not empty. - *
          • - *
          - * The intent is that this string could be supplied - * to the {@link #ObjectName(String)} constructor to - * produce an equivalent {@link ObjectName}. - *
        • - *
        • In the old serial form (value of property - * jmx.serial.form is - * 1.0): <domain> <propertyList> - * <propertyListString> <canonicalName> - * <pattern> <propertyPattern>, - * where:
            - *
          • <domain> represents the domain part - * of the {@link ObjectName}
          • - *
          • <propertyList> is the - * {@link Hashtable} that contains all the - * pairs (key,value) for this - * {@link ObjectName}
          • - *
          • <propertyListString> is the - * {@link String} representation of the - * list of properties in any order (not - * mandatorily a canonical representation) - *
          • - *
          • <canonicalName> is the - * {@link String} containing this - * {@link ObjectName}'s canonical name
          • - *
          • <pattern> is a boolean which is - * true if this - * {@link ObjectName} contains a pattern
          • - *
          • <propertyPattern> is a boolean which - * is true if this - * {@link ObjectName} contains a pattern in - * the list of properties
          • - *
          - *
        • + * @serialData The string "<domain>:<properties><wild>", where: + *
            + *
          • <domain> represents the domain part + * of the {@link ObjectName}
          • + *
          • <properties> represents the list of + * properties, as returned by + * {@link #getKeyPropertyListString}
          • + *
          • <wild> is empty if not + * isPropertyPattern, or + * is the character "*" if + * this isPropertyPattern + * and <properties> is empty, or + * is ",*" if + * isPropertyPattern and + * <properties> is not empty.
          • *
          + * The intent is that this string could be supplied + * to the {@link #ObjectName(String)} constructor to + * produce an equivalent {@link ObjectName}. */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // Read CR 6441274 before making any changes to this code - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("domain", _canonicalName.substring(0, getDomainLength())); - fields.put("propertyList", getKeyPropertyList()); - fields.put("propertyListString", getKeyPropertyListString()); - fields.put("canonicalName", _canonicalName); - fields.put("pattern", (_compressed_storage & (DOMAIN_PATTERN | PROPLIST_PATTERN)) != 0); - fields.put("propertyPattern", isPropertyListPattern()); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - out.writeObject(getSerializedNameString()); - } + out.defaultWriteObject(); + out.writeObject(getSerializedNameString()); } // Category : Serialization <=================================== diff --git a/src/java.management/share/classes/javax/management/modelmbean/DescriptorSupport.java b/src/java.management/share/classes/javax/management/modelmbean/DescriptorSupport.java index 00aa6ab7eb7..bea7ad92d0c 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/DescriptorSupport.java +++ b/src/java.management/share/classes/javax/management/modelmbean/DescriptorSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -81,69 +81,18 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class DescriptorSupport implements javax.management.Descriptor { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 8071560848919417985L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -6292969195866300415L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("descriptor", HashMap.class), - new ObjectStreamField("currClass", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("descriptor", HashMap.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = -6292969195866300415L; /** * @serialField descriptor HashMap The collection of fields representing this descriptor */ - private static final ObjectStreamField[] serialPersistentFields; - private static final String serialForm; - static { - serialForm = getForm(); - boolean compat = "1.0".equals(serialForm); // serialForm may be null - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - - @SuppressWarnings("removal") - private static String getForm() { - String form = null; - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - return AccessController.doPrivileged(act); - } catch (Exception e) { - // OK: No compat with 1.0 - return null; - } - } - - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("descriptor", HashMap.class) + }; /* Spec says that field names are case-insensitive, but that case is preserved. This means that we need to be able to map from a @@ -1286,22 +1235,8 @@ private void readObject(ObjectInputStream in) /** * Serializes a {@link DescriptorSupport} to an {@link ObjectOutputStream}. */ - /* If you set jmx.serial.form to "1.2.0" or "1.2.1", then we are - bug-compatible with those versions. Specifically, field names - are forced to lower-case before being written. This - contradicts the spec, which, though it does not mention - serialization explicitly, does say that the case of field names - is preserved. But in 1.2.0 and 1.2.1, this requirement was not - met. Instead, field names in the descriptor map were forced to - lower case. Those versions expect this to have happened to a - descriptor they deserialize and e.g. getFieldValue will not - find a field whose name is spelt with a different case. - */ private void writeObject(ObjectOutputStream out) throws IOException { ObjectOutputStream.PutField fields = out.putFields(); - boolean compat = "1.0".equals(serialForm); - if (compat) - fields.put("currClass", currClass); /* Purge the field "targetObject" from the DescriptorSupport before * serializing since the referenced object is typically not @@ -1315,15 +1250,7 @@ private void writeObject(ObjectOutputStream out) throws IOException { startMap.remove("targetObject"); } - final HashMap descriptor; - if (compat || "1.2.0".equals(serialForm) || - "1.2.1".equals(serialForm)) { - descriptor = new HashMap<>(); - for (Map.Entry entry : startMap.entrySet()) - descriptor.put(entry.getKey().toLowerCase(), entry.getValue()); - } else - descriptor = new HashMap<>(startMap); - + final HashMap descriptor = new HashMap<>(startMap); fields.put("descriptor", descriptor); out.writeFields(); } diff --git a/src/java.management/share/classes/javax/management/modelmbean/InvalidTargetObjectTypeException.java b/src/java.management/share/classes/javax/management/modelmbean/InvalidTargetObjectTypeException.java index 2c90dcaa209..d7d3bed055c 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/InvalidTargetObjectTypeException.java +++ b/src/java.management/share/classes/javax/management/modelmbean/InvalidTargetObjectTypeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -46,61 +46,16 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class InvalidTargetObjectTypeException extends Exception { - - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 3711724570458346634L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 1190536278266811217L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("msgStr", String.class), - new ObjectStreamField("relatedExcept", Exception.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("exception", Exception.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = 1190536278266811217L; /** * @serialField exception Exception Encapsulated {@link Exception} */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: No compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("exception", Exception.class) + }; /** * @serial Encapsulated {@link Exception} @@ -156,23 +111,7 @@ public InvalidTargetObjectTypeException (Exception e, String s) */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - exception = (Exception) fields.get("relatedExcept", null); - if (fields.defaulted("relatedExcept")) - { - throw new NullPointerException("relatedExcept"); - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -181,20 +120,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("relatedExcept", exception); - fields.put("msgStr", ((exception != null)?exception.getMessage():"")); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java index b4e7ecfd1e7..d30bd368a63 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java +++ b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanAttributeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -116,63 +116,19 @@ * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID is not constant public class ModelMBeanAttributeInfo extends MBeanAttributeInfo implements DescriptorAccess { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 7098036920755973145L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 6181543027787327345L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("attrDescriptor", Descriptor.class), - new ObjectStreamField("currClass", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("attrDescriptor", Descriptor.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; - /** - * @serialField attrDescriptor Descriptor The {@link Descriptor} - * containing the metadata corresponding to this attribute - */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: No compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final long serialVersionUID = 6181543027787327345L; + /** + * @serialField attrDescriptor Descriptor The {@link Descriptor} + * containing the metadata corresponding to this attribute + */ + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("attrDescriptor", Descriptor.class) + }; /** * @serial The {@link Descriptor} containing the metadata corresponding to @@ -508,21 +464,7 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("attrDescriptor", attrDescriptor); - fields.put("currClass", currClass); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java index 3b5863007a6..0b8413083ac 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java +++ b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanConstructorInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -89,63 +89,18 @@ * * @since 1.5 */ - -@SuppressWarnings("serial") // serialVersionUID is not constant public class ModelMBeanConstructorInfo extends MBeanConstructorInfo implements DescriptorAccess { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -4440125391095574518L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 3862947819818064362L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("consDescriptor", Descriptor.class), - new ObjectStreamField("currClass", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("consDescriptor", Descriptor.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; - /** - * @serialField consDescriptor Descriptor The {@link Descriptor} containing the metadata for this instance - */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: No compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final long serialVersionUID = 3862947819818064362L; + /** + * @serialField consDescriptor Descriptor The {@link Descriptor} containing the metadata for this instance + */ + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("consDescriptor", Descriptor.class) + }; /** * @serial The {@link Descriptor} containing the metadata for this instance @@ -464,21 +419,7 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("consDescriptor", consDescriptor); - fields.put("currClass", currClass); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java index bf164b678cc..a209c2c7f42 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java +++ b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanInfoSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -81,44 +81,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -3944083498453227709L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -1935722590756516193L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("modelMBeanDescriptor", Descriptor.class), - new ObjectStreamField("mmbAttributes", MBeanAttributeInfo[].class), - new ObjectStreamField("mmbConstructors", MBeanConstructorInfo[].class), - new ObjectStreamField("mmbNotifications", MBeanNotificationInfo[].class), - new ObjectStreamField("mmbOperations", MBeanOperationInfo[].class), - new ObjectStreamField("currClass", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("modelMBeanDescriptor", Descriptor.class), - new ObjectStreamField("modelMBeanAttributes", MBeanAttributeInfo[].class), - new ObjectStreamField("modelMBeanConstructors", MBeanConstructorInfo[].class), - new ObjectStreamField("modelMBeanNotifications", MBeanNotificationInfo[].class), - new ObjectStreamField("modelMBeanOperations", MBeanOperationInfo[].class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = -1935722590756516193L; /** * @serialField modelMBeanDescriptor Descriptor The descriptor containing * MBean wide policy @@ -135,27 +100,14 @@ public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { * {@link ModelMBeanOperationInfo} objects which * have descriptors */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: No compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("modelMBeanDescriptor", Descriptor.class), + new ObjectStreamField("modelMBeanAttributes", MBeanAttributeInfo[].class), + new ObjectStreamField("modelMBeanConstructors", MBeanConstructorInfo[].class), + new ObjectStreamField("modelMBeanNotifications", MBeanNotificationInfo[].class), + new ObjectStreamField("modelMBeanOperations", MBeanOperationInfo[].class) + }; /** * @serial The descriptor containing MBean wide policy @@ -957,40 +909,8 @@ private Descriptor validDescriptor(final Descriptor in) throws RuntimeOperations */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - modelMBeanDescriptor = - (Descriptor) fields.get("modelMBeanDescriptor", null); - if (fields.defaulted("modelMBeanDescriptor")) { - throw new NullPointerException("modelMBeanDescriptor"); - } - modelMBeanAttributes = - (MBeanAttributeInfo[]) fields.get("mmbAttributes", null); - if (fields.defaulted("mmbAttributes")) { - throw new NullPointerException("mmbAttributes"); - } - modelMBeanConstructors = - (MBeanConstructorInfo[]) fields.get("mmbConstructors", null); - if (fields.defaulted("mmbConstructors")) { - throw new NullPointerException("mmbConstructors"); - } - modelMBeanNotifications = - (MBeanNotificationInfo[]) fields.get("mmbNotifications", null); - if (fields.defaulted("mmbNotifications")) { - throw new NullPointerException("mmbNotifications"); - } - modelMBeanOperations = - (MBeanOperationInfo[]) fields.get("mmbOperations", null); - if (fields.defaulted("mmbOperations")) { - throw new NullPointerException("mmbOperations"); - } - } else { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + + in.defaultReadObject(); } @@ -999,22 +919,7 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("modelMBeanDescriptor", modelMBeanDescriptor); - fields.put("mmbAttributes", modelMBeanAttributes); - fields.put("mmbConstructors", modelMBeanConstructors); - fields.put("mmbNotifications", modelMBeanNotifications); - fields.put("mmbOperations", modelMBeanOperations); - fields.put("currClass", currClass); - out.writeFields(); - } else { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } diff --git a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java index 1f6cf566ba3..c0bce84a5d9 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java +++ b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -96,64 +96,19 @@ * * @since 1.5 */ - -@SuppressWarnings("serial") // serialVersionUID is not constant public class ModelMBeanNotificationInfo extends MBeanNotificationInfo implements DescriptorAccess { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form - // depends on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -5211564525059047097L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -7445681389570207141L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("notificationDescriptor", Descriptor.class), - new ObjectStreamField("currClass", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("notificationDescriptor", Descriptor.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = -7445681389570207141L; /** * @serialField notificationDescriptor Descriptor The descriptor * containing the appropriate metadata for this instance */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: No compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("notificationDescriptor", Descriptor.class) + }; /** * @serial The descriptor containing the appropriate metadata for @@ -398,18 +353,7 @@ private void readObject(ObjectInputStream in) **/ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("notificationDescriptor", notificationDescriptor); - fields.put("currClass", currClass); - out.writeFields(); - } else { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java index 5550be20d6f..1d22b41b1e8 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java +++ b/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanOperationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -108,64 +108,19 @@ * * @since 1.5 */ - -@SuppressWarnings("serial") // serialVersionUID is not constant public class ModelMBeanOperationInfo extends MBeanOperationInfo implements DescriptorAccess { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 9087646304346171239L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 6532732096650090465L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("operationDescriptor", Descriptor.class), - new ObjectStreamField("currClass", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("operationDescriptor", Descriptor.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; - /** - * @serialField operationDescriptor Descriptor The descriptor - * containing the appropriate metadata for this instance - */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: No compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final long serialVersionUID = 6532732096650090465L; + /** + * @serialField operationDescriptor Descriptor The descriptor + * containing the appropriate metadata for this instance + */ + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("operationDescriptor", Descriptor.class) + }; /** * @serial The descriptor containing the appropriate metadata for this instance @@ -515,21 +470,7 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("operationDescriptor", operationDescriptor); - fields.put("currClass", currClass); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // out.defaultWriteObject(); - } } } diff --git a/src/java.management/share/classes/javax/management/modelmbean/XMLParseException.java b/src/java.management/share/classes/javax/management/modelmbean/XMLParseException.java index 2be6f37bf3b..daa1abf039e 100644 --- a/src/java.management/share/classes/javax/management/modelmbean/XMLParseException.java +++ b/src/java.management/share/classes/javax/management/modelmbean/XMLParseException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -49,54 +49,10 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class XMLParseException extends Exception { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -7780049316655891976L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 3176664577895105181L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("msgStr", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = { }; - // - // Actual serial version and serial form - private static final long serialVersionUID; - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK: No compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final long serialVersionUID = 3176664577895105181L; /** * Default constructor . @@ -141,19 +97,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("msgStr", getMessage()); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/relation/MBeanServerNotificationFilter.java b/src/java.management/share/classes/javax/management/relation/MBeanServerNotificationFilter.java index d02d15cb1e5..7579e416e36 100644 --- a/src/java.management/share/classes/javax/management/relation/MBeanServerNotificationFilter.java +++ b/src/java.management/share/classes/javax/management/relation/MBeanServerNotificationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -57,37 +57,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID must be constant public class MBeanServerNotificationFilter extends NotificationFilterSupport { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 6001782699077323605L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 2605900539589789736L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("mySelectObjNameList", Vector.class), - new ObjectStreamField("myDeselectObjNameList", Vector.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("selectedNames", List.class), - new ObjectStreamField("deselectedNames", List.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = 2605900539589789736L; /** * @serialField selectedNames List List of {@link ObjectName}s of interest *
            @@ -102,27 +74,11 @@ public class MBeanServerNotificationFilter extends NotificationFilterSupport { *
          • Empty vector means that no {@link ObjectName} is explicitly deselected
          • *
          */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK : Too bad, no compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("selectedNames", List.class), + new ObjectStreamField("deselectedNames", List.class) + }; // // Private members @@ -405,28 +361,7 @@ public synchronized boolean isNotificationEnabled(Notification notif) */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - selectedNames = cast(fields.get("mySelectObjNameList", null)); - if (fields.defaulted("mySelectObjNameList")) - { - throw new NullPointerException("mySelectObjNameList"); - } - deselectedNames = cast(fields.get("myDeselectObjNameList", null)); - if (fields.defaulted("myDeselectObjNameList")) - { - throw new NullPointerException("myDeselectObjNameList"); - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -435,20 +370,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("mySelectObjNameList", selectedNames); - fields.put("myDeselectObjNameList", deselectedNames); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/relation/RelationNotification.java b/src/java.management/share/classes/javax/management/relation/RelationNotification.java index 11c2fab163e..16d660bc07f 100644 --- a/src/java.management/share/classes/javax/management/relation/RelationNotification.java +++ b/src/java.management/share/classes/javax/management/relation/RelationNotification.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -57,47 +57,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class RelationNotification extends Notification { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -2126464566505527147L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -6871117877523310399L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("myNewRoleValue", ArrayList.class), - new ObjectStreamField("myOldRoleValue", ArrayList.class), - new ObjectStreamField("myRelId", String.class), - new ObjectStreamField("myRelObjName", ObjectName.class), - new ObjectStreamField("myRelTypeName", String.class), - new ObjectStreamField("myRoleName", String.class), - new ObjectStreamField("myUnregMBeanList", ArrayList.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("newRoleValue", List.class), - new ObjectStreamField("oldRoleValue", List.class), - new ObjectStreamField("relationId", String.class), - new ObjectStreamField("relationObjName", ObjectName.class), - new ObjectStreamField("relationTypeName", String.class), - new ObjectStreamField("roleName", String.class), - new ObjectStreamField("unregisterMBeanList", List.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = -6871117877523310399L; /** * @serialField relationId String Relation identifier of * created/removed/updated relation @@ -115,27 +77,16 @@ public class RelationNotification extends Notification { * @serialField newRoleValue List New role value ({@link * ArrayList} of {@link ObjectName}s) (only for role update) */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK : Too bad, no compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("newRoleValue", List.class), + new ObjectStreamField("oldRoleValue", List.class), + new ObjectStreamField("relationId", String.class), + new ObjectStreamField("relationObjName", ObjectName.class), + new ObjectStreamField("relationTypeName", String.class), + new ObjectStreamField("roleName", String.class), + new ObjectStreamField("unregisterMBeanList", List.class) + }; // // Notification types @@ -541,26 +492,14 @@ private void readObject(ObjectInputStream in) ObjectInputStream.GetField fields = in.readFields(); - if (compat) { - tmpRelationId = (String)fields.get("myRelId", null); - tmpRelationTypeName = (String)fields.get("myRelTypeName", null); - tmpRoleName = (String)fields.get("myRoleName", null); + tmpRelationId = (String)fields.get("relationId", null); + tmpRelationTypeName = (String)fields.get("relationTypeName", null); + tmpRoleName = (String)fields.get("roleName", null); - tmpRelationObjName = (ObjectName)fields.get("myRelObjName", null); - tmpNewRoleValue = cast(fields.get("myNewRoleValue", null)); - tmpOldRoleValue = cast(fields.get("myOldRoleValue", null)); - tmpUnregMBeanList = cast(fields.get("myUnregMBeanList", null)); - } - else { - tmpRelationId = (String)fields.get("relationId", null); - tmpRelationTypeName = (String)fields.get("relationTypeName", null); - tmpRoleName = (String)fields.get("roleName", null); - - tmpRelationObjName = (ObjectName)fields.get("relationObjName", null); - tmpNewRoleValue = cast(fields.get("newRoleValue", null)); - tmpOldRoleValue = cast(fields.get("oldRoleValue", null)); - tmpUnregMBeanList = cast(fields.get("unregisterMBeanList", null)); - } + tmpRelationObjName = (ObjectName)fields.get("relationObjName", null); + tmpNewRoleValue = cast(fields.get("newRoleValue", null)); + tmpOldRoleValue = cast(fields.get("oldRoleValue", null)); + tmpUnregMBeanList = cast(fields.get("unregisterMBeanList", null)); // Validate fields we just read, throw InvalidObjectException // if something goes wrong @@ -591,25 +530,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("myNewRoleValue", newRoleValue); - fields.put("myOldRoleValue", oldRoleValue); - fields.put("myRelId", relationId); - fields.put("myRelObjName", relationObjName); - fields.put("myRelTypeName", relationTypeName); - fields.put("myRoleName",roleName); - fields.put("myUnregMBeanList", unregisterMBeanList); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/relation/RelationTypeSupport.java b/src/java.management/share/classes/javax/management/relation/RelationTypeSupport.java index 5038fed2cfe..766c42ca780 100644 --- a/src/java.management/share/classes/javax/management/relation/RelationTypeSupport.java +++ b/src/java.management/share/classes/javax/management/relation/RelationTypeSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -63,39 +63,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class RelationTypeSupport implements RelationType { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -8179019472410837190L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 4611072955724144607L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("myTypeName", String.class), - new ObjectStreamField("myRoleName2InfoMap", HashMap.class), - new ObjectStreamField("myIsInRelServFlg", boolean.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("typeName", String.class), - new ObjectStreamField("roleName2InfoMap", Map.class), - new ObjectStreamField("isInRelationService", boolean.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = 4611072955724144607L; /** * @serialField typeName String Relation type name * @serialField roleName2InfoMap Map {@link Map} holding the mapping: @@ -103,27 +73,12 @@ public class RelationTypeSupport implements RelationType { * @serialField isInRelationService boolean Flag specifying whether the relation type has been declared in the * Relation Service (so can no longer be updated) */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK : Too bad, no compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("typeName", String.class), + new ObjectStreamField("roleName2InfoMap", Map.class), + new ObjectStreamField("isInRelationService", boolean.class) + }; // // Private members @@ -421,33 +376,7 @@ static void checkRoleInfos(RoleInfo[] roleInfoArray) */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - typeName = (String) fields.get("myTypeName", null); - if (fields.defaulted("myTypeName")) - { - throw new NullPointerException("myTypeName"); - } - roleName2InfoMap = cast(fields.get("myRoleName2InfoMap", null)); - if (fields.defaulted("myRoleName2InfoMap")) - { - throw new NullPointerException("myRoleName2InfoMap"); - } - isInRelationService = fields.get("myIsInRelServFlg", false); - if (fields.defaulted("myIsInRelServFlg")) - { - throw new NullPointerException("myIsInRelServFlg"); - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -456,21 +385,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("myTypeName", typeName); - fields.put("myRoleName2InfoMap", roleName2InfoMap); - fields.put("myIsInRelServFlg", isInRelationService); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/relation/Role.java b/src/java.management/share/classes/javax/management/relation/Role.java index 60accb2e007..431092a3b48 100644 --- a/src/java.management/share/classes/javax/management/relation/Role.java +++ b/src/java.management/share/classes/javax/management/relation/Role.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -51,62 +51,18 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class Role implements Serializable { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -1959486389343113026L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -279985518429862552L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("myName", String.class), - new ObjectStreamField("myObjNameList", ArrayList.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("name", String.class), - new ObjectStreamField("objectNameList", List.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = -279985518429862552L; /** * @serialField name String Role name * @serialField objectNameList List {@link List} of {@link ObjectName}s of referenced MBeans */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK : Too bad, no compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("name", String.class), + new ObjectStreamField("objectNameList", List.class) + }; // // Private members @@ -290,28 +246,7 @@ public static String roleValueToString(List roleValue) */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - name = (String) fields.get("myName", null); - if (fields.defaulted("myName")) - { - throw new NullPointerException("myName"); - } - objectNameList = cast(fields.get("myObjNameList", null)); - if (fields.defaulted("myObjNameList")) - { - throw new NullPointerException("myObjNameList"); - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -320,20 +255,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("myName", name); - fields.put("myObjNameList", objectNameList); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/relation/RoleInfo.java b/src/java.management/share/classes/javax/management/relation/RoleInfo.java index 23258ce8c72..6f2926005e9 100644 --- a/src/java.management/share/classes/javax/management/relation/RoleInfo.java +++ b/src/java.management/share/classes/javax/management/relation/RoleInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -46,47 +46,9 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class RoleInfo implements Serializable { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 7227256952085334351L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = 2504952983494636987L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("myName", String.class), - new ObjectStreamField("myIsReadableFlg", boolean.class), - new ObjectStreamField("myIsWritableFlg", boolean.class), - new ObjectStreamField("myDescription", String.class), - new ObjectStreamField("myMinDegree", int.class), - new ObjectStreamField("myMaxDegree", int.class), - new ObjectStreamField("myRefMBeanClassName", String.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("name", String.class), - new ObjectStreamField("isReadable", boolean.class), - new ObjectStreamField("isWritable", boolean.class), - new ObjectStreamField("description", String.class), - new ObjectStreamField("minDegree", int.class), - new ObjectStreamField("maxDegree", int.class), - new ObjectStreamField("referencedMBeanClassName", String.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = 2504952983494636987L; /** * @serialField name String Role name * @serialField isReadable boolean Read access mode: {@code true} if role is readable @@ -96,27 +58,16 @@ public class RoleInfo implements Serializable { * @serialField maxDegree int Maximum degree (i.e. maximum number of referenced MBeans in corresponding role) * @serialField referencedMBeanClassName String Name of class of MBean(s) expected to be referenced in corresponding role */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK : Too bad, no compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("name", String.class), + new ObjectStreamField("isReadable", boolean.class), + new ObjectStreamField("isWritable", boolean.class), + new ObjectStreamField("description", String.class), + new ObjectStreamField("minDegree", int.class), + new ObjectStreamField("maxDegree", int.class), + new ObjectStreamField("referencedMBeanClassName", String.class) + }; // // Public constants @@ -530,53 +481,7 @@ private void init(String roleName, */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - name = (String) fields.get("myName", null); - if (fields.defaulted("myName")) - { - throw new NullPointerException("myName"); - } - isReadable = fields.get("myIsReadableFlg", false); - if (fields.defaulted("myIsReadableFlg")) - { - throw new NullPointerException("myIsReadableFlg"); - } - isWritable = fields.get("myIsWritableFlg", false); - if (fields.defaulted("myIsWritableFlg")) - { - throw new NullPointerException("myIsWritableFlg"); - } - description = (String) fields.get("myDescription", null); - if (fields.defaulted("myDescription")) - { - throw new NullPointerException("myDescription"); - } - minDegree = fields.get("myMinDegree", 0); - if (fields.defaulted("myMinDegree")) - { - throw new NullPointerException("myMinDegree"); - } - maxDegree = fields.get("myMaxDegree", 0); - if (fields.defaulted("myMaxDegree")) - { - throw new NullPointerException("myMaxDegree"); - } - referencedMBeanClassName = (String) fields.get("myRefMBeanClassName", null); - if (fields.defaulted("myRefMBeanClassName")) - { - throw new NullPointerException("myRefMBeanClassName"); - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -585,26 +490,7 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("myName", name); - fields.put("myIsReadableFlg", isReadable); - fields.put("myIsWritableFlg", isWritable); - fields.put("myDescription", description); - fields.put("myMinDegree", minDegree); - fields.put("myMaxDegree", maxDegree); - fields.put("myRefMBeanClassName", referencedMBeanClassName); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/relation/RoleResult.java b/src/java.management/share/classes/javax/management/relation/RoleResult.java index 60836c897e5..7f98a7f7a24 100644 --- a/src/java.management/share/classes/javax/management/relation/RoleResult.java +++ b/src/java.management/share/classes/javax/management/relation/RoleResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -44,62 +44,18 @@ * * @since 1.5 */ -@SuppressWarnings("serial") public class RoleResult implements Serializable { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = 3786616013762091099L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -6304063118040985512L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("myRoleList", RoleList.class), - new ObjectStreamField("myRoleUnresList", RoleUnresolvedList.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = - { - new ObjectStreamField("roleList", RoleList.class), - new ObjectStreamField("unresolvedRoleList", RoleUnresolvedList.class) - }; - // - // Actual serial version and serial form - private static final long serialVersionUID; + private static final long serialVersionUID = -6304063118040985512L; /** * @serialField roleList RoleList List of roles successfully accessed * @serialField unresolvedRoleList RoleUnresolvedList List of roles unsuccessfully accessed */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK : Too bad, no compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("roleList", RoleList.class), + new ObjectStreamField("unresolvedRoleList", RoleUnresolvedList.class) + }; // // Private members @@ -206,28 +162,7 @@ public void setRolesUnresolved(RoleUnresolvedList unresolvedList) { */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - roleList = (RoleList) fields.get("myRoleList", null); - if (fields.defaulted("myRoleList")) - { - throw new NullPointerException("myRoleList"); - } - unresolvedRoleList = (RoleUnresolvedList) fields.get("myRoleUnresList", null); - if (fields.defaulted("myRoleUnresList")) - { - throw new NullPointerException("myRoleUnresList"); - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -236,20 +171,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("myRoleList", roleList); - fields.put("myRoleUnresList", unresolvedRoleList); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.management/share/classes/javax/management/relation/RoleUnresolved.java b/src/java.management/share/classes/javax/management/relation/RoleUnresolved.java index 169b1263fdb..36b6dff9d71 100644 --- a/src/java.management/share/classes/javax/management/relation/RoleUnresolved.java +++ b/src/java.management/share/classes/javax/management/relation/RoleUnresolved.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -52,64 +52,19 @@ * * @since 1.5 */ -@SuppressWarnings("serial") // serialVersionUID not constant public class RoleUnresolved implements Serializable { - // Serialization compatibility stuff: - // Two serial forms are supported in this class. The selected form depends - // on system property "jmx.serial.form": - // - "1.0" for JMX 1.0 - // - any other value for JMX 1.1 and higher - // - // Serial version for old serial form - private static final long oldSerialVersionUID = -9026457686611660144L; - // - // Serial version for new serial form - private static final long newSerialVersionUID = -48350262537070138L; - // - // Serializable fields in old serial form - private static final ObjectStreamField[] oldSerialPersistentFields = - { - new ObjectStreamField("myRoleName", String.class), - new ObjectStreamField("myRoleValue", ArrayList.class), - new ObjectStreamField("myPbType", int.class) - }; - // - // Serializable fields in new serial form - private static final ObjectStreamField[] newSerialPersistentFields = + private static final long serialVersionUID = -48350262537070138L; + /** @serialField roleName String Role name + * @serialField roleValue List Role value ({@link List} of {@link ObjectName} objects) + * @serialField problemType int Problem type + */ + private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("roleName", String.class), new ObjectStreamField("roleValue", List.class), new ObjectStreamField("problemType", int.class) }; - // - // Actual serial version and serial form - private static final long serialVersionUID; - /** @serialField roleName String Role name - * @serialField roleValue List Role value ({@link List} of {@link ObjectName} objects) - * @serialField problemType int Problem type - */ - private static final ObjectStreamField[] serialPersistentFields; - private static boolean compat = false; - static { - try { - GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); - @SuppressWarnings("removal") - String form = AccessController.doPrivileged(act); - compat = (form != null && form.equals("1.0")); - } catch (Exception e) { - // OK : Too bad, no compat with 1.0 - } - if (compat) { - serialPersistentFields = oldSerialPersistentFields; - serialVersionUID = oldSerialVersionUID; - } else { - serialPersistentFields = newSerialPersistentFields; - serialVersionUID = newSerialVersionUID; - } - } - // - // END Serialization compatibility stuff // // Private members @@ -304,33 +259,7 @@ public String toString() { */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - if (compat) - { - // Read an object serialized in the old serial form - // - ObjectInputStream.GetField fields = in.readFields(); - roleName = (String) fields.get("myRoleName", null); - if (fields.defaulted("myRoleName")) - { - throw new NullPointerException("myRoleName"); - } - roleValue = cast(fields.get("myRoleValue", null)); - if (fields.defaulted("myRoleValue")) - { - throw new NullPointerException("myRoleValue"); - } - problemType = fields.get("myPbType", 0); - if (fields.defaulted("myPbType")) - { - throw new NullPointerException("myPbType"); - } - } - else - { - // Read an object serialized in the new serial form - // - in.defaultReadObject(); - } + in.defaultReadObject(); } @@ -339,21 +268,6 @@ private void readObject(ObjectInputStream in) */ private void writeObject(ObjectOutputStream out) throws IOException { - if (compat) - { - // Serializes this instance in the old serial form - // - ObjectOutputStream.PutField fields = out.putFields(); - fields.put("myRoleName", roleName); - fields.put("myRoleValue", roleValue); - fields.put("myPbType", problemType); - out.writeFields(); - } - else - { - // Serializes this instance in the new serial form - // - out.defaultWriteObject(); - } + out.defaultWriteObject(); } } diff --git a/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java b/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java index 544c1945701..5535fdd41c9 100644 --- a/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java +++ b/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java @@ -144,7 +144,7 @@ final class DigestMD5Client extends DigestMD5Base implements SaslClient { * combined protocol and host being used for authentication. * @param props The possibly null properties to be used by the SASL * mechanism to configure the authentication exchange. - * @param cbh The non-null CallbackHanlder object for callbacks + * @param cbh The non-null CallbackHandler object for callbacks * @throws SaslException if no authentication ID or password is supplied */ DigestMD5Client(String authzid, String protocol, String serverName, diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java index ee1f40dc196..ada07bb1bae 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/ClassTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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,10 +43,10 @@ * * * @jls 8.1 Class Declarations - * @jls 8.9 Enum Types - * @jls 8.10 Record Types + * @jls 8.9 Enum Classes + * @jls 8.10 Record Classes * @jls 9.1 Interface Declarations - * @jls 9.6 Annotation Types + * @jls 9.6 Annotation Interfaces * * @author Peter von der Ahé * @author Jonathan Gibbons diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java index f5bede70539..f752f7f3191 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ * expression instanceof type * * - * @jls 15.20.2 Type Comparison Operator instanceof + * @jls 15.20.2 The instanceof Operator * * @author Peter von der Ahé * @author Jonathan Gibbons diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/LiteralTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/LiteralTree.java index 622e4588703..8899e3699b6 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/LiteralTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/LiteralTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -34,7 +34,7 @@ * value * * - * @jls 15.28 Constant Expressions + * @jls 15.29 Constant Expressions * * @author Peter von der Ahé * @author Jonathan Gibbons diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/MethodTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/MethodTree.java index f6dae4c3ced..9215da58772 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/MethodTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/MethodTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -44,7 +44,7 @@ * @jls 8.6 Instance Initializers * @jls 8.7 Static Initializers * @jls 9.4 Method Declarations - * @jls 9.6.1 Annotation Type Elements + * @jls 9.6.1 Annotation Interface Elements * * @author Peter von der Ahé * @author Jonathan Gibbons diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/ModifiersTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/ModifiersTree.java index a193d4516e3..dbb2e5e2183 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/ModifiersTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/ModifiersTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -40,9 +40,9 @@ * * * @jls 8.1.1 Class Modifiers + * @jls 8.1.3 Inner Classes and Enclosing Instances * @jls 8.3.1 Field Modifiers * @jls 8.4.3 Method Modifiers - * @jls 8.5.1 Static Member Type Declarations * @jls 8.8.3 Constructor Modifiers * @jls 9.1.1 Interface Modifiers * @jls 9.7 Annotations diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/StatementTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/StatementTree.java index d3c4b252473..9c103505fba 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/StatementTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/StatementTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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,7 +29,7 @@ * A tree node used as the base class for the different kinds of * statements. * - * @jls 14 Blocks and Statements + * @jls 14 Blocks, Statements, and Patterns * * @author Peter von der Ahé * @author Jonathan Gibbons diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java index 2327c7a3f49..35129667946 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * } * * - * @jls 15.29 Switch Expressions + * @jls 15.28 {@code switch} Expressions * * @since 14 */ diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/VariableTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/VariableTree.java index d63fa308e3b..a1191b2f8e6 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/VariableTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/VariableTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * * * @jls 8.3 Field Declarations - * @jls 14.4 Local Variable Declaration Statements + * @jls 14.4 Local Variable Declarations * * @author Peter von der Ahé * @author Jonathan Gibbons diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 792b5ca2346..29ab8435ada 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -827,30 +827,33 @@ private boolean exhausts(JCExpression selector, List cases) { } } Set patterns = patternSet; - boolean genericPatternsExpanded = false; + boolean useHashes = true; try { boolean repeat = true; while (repeat) { Set updatedPatterns; updatedPatterns = reduceBindingPatterns(selector.type, patterns); - updatedPatterns = reduceNestedPatterns(updatedPatterns); + updatedPatterns = reduceNestedPatterns(updatedPatterns, useHashes); updatedPatterns = reduceRecordPatterns(updatedPatterns); updatedPatterns = removeCoveredRecordPatterns(updatedPatterns); repeat = !updatedPatterns.equals(patterns); if (checkCovered(selector.type, patterns)) { return true; } - if (!repeat && !genericPatternsExpanded) { + if (!repeat) { //there may be situation like: - //class B extends S1, S2 + //class B permits S1, S2 //patterns: R(S1, B), R(S2, S2) - //this should be joined to R(B, S2), + //this might be joined to R(B, S2), as B could be rewritten to S2 //but hashing in reduceNestedPatterns will not allow that - //attempt to once expand all types to their transitive permitted types, - //on all depth of nesting: - updatedPatterns = expandGenericPatterns(updatedPatterns); - genericPatternsExpanded = true; - repeat = !updatedPatterns.equals(patterns); + //disable the use of hashing, and use subtyping in + //reduceNestedPatterns to handle situations like this: + repeat = useHashes; + useHashes = false; + } else { + //if a reduction happened, make sure hashing in reduceNestedPatterns + //is enabled, as the hashing speeds up the process significantly: + useHashes = true; } patterns = updatedPatterns; } @@ -1023,8 +1026,15 @@ private List baseClasses(TypeSymbol root) { * simplify the pattern. If that succeeds, the original found sub-set * of patterns is replaced with a new set of patterns of the form: * $record($prefix$, $resultOfReduction, $suffix$) + * + * useHashes: when true, patterns will be subject to exact equivalence; + * when false, two binding patterns will be considered equivalent + * if one of them is more generic than the other one; + * when false, the processing will be significantly slower, + * as pattern hashes cannot be used to speed up the matching process */ - private Set reduceNestedPatterns(Set patterns) { + private Set reduceNestedPatterns(Set patterns, + boolean useHashes) { /* implementation note: * finding a sub-set of patterns that only differ in a single * column is time-consuming task, so this method speeds it up by: @@ -1049,13 +1059,13 @@ private Set reduceNestedPatterns(Set pat mismatchingCandidate < nestedPatternsCount; mismatchingCandidate++) { int mismatchingCandidateFin = mismatchingCandidate; - var groupByHashes = + var groupEquivalenceCandidates = current .stream() //error recovery, ignore patterns with incorrect number of nested patterns: .filter(pd -> pd.nested.length == nestedPatternsCount) - .collect(groupingBy(pd -> pd.hashCode(mismatchingCandidateFin))); - for (var candidates : groupByHashes.values()) { + .collect(groupingBy(pd -> useHashes ? pd.hashCode(mismatchingCandidateFin) : 0)); + for (var candidates : groupEquivalenceCandidates.values()) { var candidatesArr = candidates.toArray(RecordPattern[]::new); for (int firstCandidate = 0; @@ -1076,9 +1086,18 @@ private Set reduceNestedPatterns(Set pat RecordPattern rpOther = candidatesArr[nextCandidate]; if (rpOne.recordType.tsym == rpOther.recordType.tsym) { for (int i = 0; i < rpOne.nested.length; i++) { - if (i != mismatchingCandidate && - !rpOne.nested[i].equals(rpOther.nested[i])) { - continue NEXT_PATTERN; + if (i != mismatchingCandidate) { + if (!rpOne.nested[i].equals(rpOther.nested[i])) { + if (useHashes || + //when not using hashes, + //check if rpOne.nested[i] is + //a subtype of rpOther.nested[i]: + !(rpOne.nested[i] instanceof BindingPattern bpOne) || + !(rpOther.nested[i] instanceof BindingPattern bpOther) || + !types.isSubtype(types.erasure(bpOne.type), types.erasure(bpOther.type))) { + continue NEXT_PATTERN; + } + } } } join.append(rpOther); @@ -1086,14 +1105,16 @@ private Set reduceNestedPatterns(Set pat } var nestedPatterns = join.stream().map(rp -> rp.nested[mismatchingCandidateFin]).collect(Collectors.toSet()); - var updatedPatterns = reduceNestedPatterns(nestedPatterns); + var updatedPatterns = reduceNestedPatterns(nestedPatterns, useHashes); updatedPatterns = reduceRecordPatterns(updatedPatterns); updatedPatterns = removeCoveredRecordPatterns(updatedPatterns); updatedPatterns = reduceBindingPatterns(rpOne.fullComponentTypes()[mismatchingCandidateFin], updatedPatterns); if (!nestedPatterns.equals(updatedPatterns)) { - current.removeAll(join); + if (useHashes) { + current.removeAll(join); + } for (PatternDescription nested : updatedPatterns) { PatternDescription[] newNested = @@ -1169,40 +1190,6 @@ private PatternDescription reduceRecordPattern(PatternDescription pattern) { return pattern; } - private Set expandGenericPatterns(Set patterns) { - var newPatterns = new HashSet(patterns); - boolean modified; - do { - modified = false; - for (PatternDescription pd : patterns) { - if (pd instanceof RecordPattern rpOne) { - for (int i = 0; i < rpOne.nested.length; i++) { - Set toExpand = Set.of(rpOne.nested[i]); - Set expanded = expandGenericPatterns(toExpand); - if (expanded != toExpand) { - expanded.removeAll(toExpand); - for (PatternDescription exp : expanded) { - PatternDescription[] newNested = Arrays.copyOf(rpOne.nested, rpOne.nested.length); - newNested[i] = exp; - modified |= newPatterns.add(new RecordPattern(rpOne.recordType(), rpOne.fullComponentTypes(), newNested)); - } - } - } - } else if (pd instanceof BindingPattern bp) { - Set permittedSymbols = allPermittedSubTypes(bp.type.tsym, cs -> true); - - if (!permittedSymbols.isEmpty()) { - for (Symbol permitted : permittedSymbols) { - //TODO infer.instantiatePatternType(selectorType, csym); (?) - modified |= newPatterns.add(new BindingPattern(permitted.type)); - } - } - } - } - } while (modified); - return newPatterns; - } - private Set removeCoveredRecordPatterns(Set patterns) { Set existingBindings = patterns.stream() .filter(pd -> pd instanceof BindingPattern) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index bd05cf91e91..2373f869b0a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -218,6 +218,12 @@ public class ClassReader { */ int[] parameterAccessFlags; + /** + * A table to hold the access flags of the method parameters, + * for all parameters including synthetic and mandated ones. + */ + int[] allParameterAccessFlags; + /** * A table to hold annotations for method parameters. */ @@ -1146,12 +1152,15 @@ protected void read(Symbol sym, int attrlen) { int newbp = bp + attrlen; if (saveParameterNames) { int numEntries = nextByte(); + allParameterAccessFlags = new int[numEntries]; parameterNameIndicesMp = new int[numEntries]; parameterAccessFlags = new int[numEntries]; + int allParamIndex = 0; int index = 0; for (int i = 0; i < numEntries; i++) { int nameIndex = nextChar(); int flags = nextChar(); + allParameterAccessFlags[allParamIndex++] = flags; if ((flags & (Flags.MANDATED | Flags.SYNTHETIC)) != 0) { continue; } @@ -1593,7 +1602,16 @@ void readParameterAnnotations(Symbol meth) { if (parameterAnnotations == null) { parameterAnnotations = new ParameterAnnotations[numParameters]; } else if (parameterAnnotations.length != numParameters) { - throw badClassFile("bad.runtime.invisible.param.annotations", meth); + //the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations + //provide annotations for a different number of parameters, ignore: + if (lintClassfile) { + log.warning(LintCategory.CLASSFILE, Warnings.RuntimeVisibleInvisibleParamAnnotationsMismatch(currentClassFile)); + } + for (int pnum = 0; pnum < numParameters; pnum++) { + readAnnotations(); + } + parameterAnnotations = null; + return ; } for (int pnum = 0; pnum < numParameters; pnum++) { if (parameterAnnotations[pnum] == null) { @@ -2623,7 +2641,8 @@ MethodSymbol readMethod() { char rawFlags = nextChar(); long flags = adjustMethodFlags(rawFlags); Name name = poolReader.getName(nextChar()); - Type type = poolReader.getType(nextChar()); + Type descriptorType = poolReader.getType(nextChar()); + Type type = descriptorType; if (currentOwner.isInterface() && (flags & ABSTRACT) == 0 && !name.equals(names.clinit)) { if (majorVersion > Version.V52.major || @@ -2640,6 +2659,7 @@ MethodSymbol readMethod() { } } validateMethodType(name, type); + boolean forceLocal = false; if (name == names.init && currentOwner.hasOuterInstance()) { // Sometimes anonymous classes don't have an outer // instance, however, there is no reliable way to tell so @@ -2647,7 +2667,8 @@ MethodSymbol readMethod() { // ditto for local classes. Local classes that have an enclosing method set // won't pass the "hasOuterInstance" check above, but those that don't have an // enclosing method (i.e. from initializers) will pass that check. - boolean local = !currentOwner.owner.members().includes(currentOwner, LookupKind.NON_RECURSIVE); + boolean local = forceLocal = + !currentOwner.owner.members().includes(currentOwner, LookupKind.NON_RECURSIVE); if (!currentOwner.name.isEmpty() && !local) type = new MethodType(adjustMethodParams(flags, type.getParameterTypes()), type.getReturnType(), @@ -2668,6 +2689,7 @@ MethodSymbol readMethod() { currentOwner = prevOwner; } validateMethodType(name, m.type); + adjustParameterAnnotations(m, descriptorType, forceLocal); setParameters(m, type); if (Integer.bitCount(rawFlags & (PUBLIC | PRIVATE | PROTECTED)) > 1) @@ -2795,17 +2817,141 @@ void setParameters(MethodSymbol sym, Type jvmType) { nameIndexMp++; annotationIndex++; } - if (parameterAnnotations != null && parameterAnnotations.length != annotationIndex) { - throw badClassFile("bad.runtime.invisible.param.annotations", sym); - } + Assert.check(parameterAnnotations == null || + parameterAnnotations.length == annotationIndex); Assert.checkNull(sym.params); sym.params = params.toList(); parameterAnnotations = null; parameterNameIndicesLvt = null; parameterNameIndicesMp = null; + allParameterAccessFlags = null; parameterAccessFlags = null; } + void adjustParameterAnnotations(MethodSymbol sym, Type methodDescriptor, + boolean forceLocal) { + if (parameterAnnotations == null) { + return ; + } + + //the specification for Runtime(In)VisibleParameterAnnotations does not + //enforce any mapping between the method parameters and the recorded + //parameter annotation. Attempt a number of heuristics to adjust the + //adjust parameterAnnotations to the percieved number of parameters: + + int methodParameterCount = sym.type.getParameterTypes().size(); + + if (methodParameterCount == parameterAnnotations.length) { + //we've got exactly as many parameter annotations as are parameters + //of the method (after considering a possible Signature attribute), + //no need to do anything. the parameter creation code will use + //the 1-1 mapping to restore the annotations: + return ; + } + + if (allParameterAccessFlags != null) { + //MethodParameters attribute present, use it: + + //count the number of non-synthetic and non-mandatory parameters: + int realParameters = 0; + + for (int i = 0; i < allParameterAccessFlags.length; i++) { + if ((allParameterAccessFlags[i] & (SYNTHETIC | MANDATED)) == 0) { + realParameters++; + } + } + + int methodDescriptorParameterCount = methodDescriptor.getParameterTypes().size(); + + if (realParameters == parameterAnnotations.length && + allParameterAccessFlags.length == methodDescriptorParameterCount) { + //if we have parameter annotations for each non-synthetic/mandatory parameter, + //and if Signature was not present, expand the parameterAnnotations to cover + //all the method descriptor's parameters: + if (sym.type == methodDescriptor) { + ParameterAnnotations[] newParameterAnnotations = + new ParameterAnnotations[methodParameterCount]; + int srcIndex = 0; + + for (int i = 0; i < methodParameterCount; i++) { + if ((allParameterAccessFlags[i] & (SYNTHETIC | MANDATED)) == 0) { + newParameterAnnotations[i] = parameterAnnotations[srcIndex++]; + } + } + + parameterAnnotations = newParameterAnnotations; + } else { + dropParameterAnnotations(); + } + } else if (realParameters == methodParameterCount && + methodDescriptorParameterCount == parameterAnnotations.length && + allParameterAccessFlags.length == methodDescriptorParameterCount) { + //if there are as many parameter annotations as parameters in + //the method descriptor, and as many real parameters as parameters + //in the method's type (after accounting for Signature), shrink + //the parameterAnnotations to only cover the parameters from + //the method's type: + ParameterAnnotations[] newParameterAnnotations = + new ParameterAnnotations[methodParameterCount]; + int targetIndex = 0; + + for (int i = 0; i < parameterAnnotations.length; i++) { + if ((allParameterAccessFlags[i] & (SYNTHETIC | MANDATED)) == 0) { + newParameterAnnotations[targetIndex++] = parameterAnnotations[i]; + } + } + + parameterAnnotations = newParameterAnnotations; + } else { + dropParameterAnnotations(); + } + return ; + } + + if (!sym.isConstructor()) { + //if the number of parameter annotations and the number of parameters + //don't match, we don't have any heuristics to map one to the other + //unless the method is a constructor: + dropParameterAnnotations(); + return ; + } + + if (sym.owner.isEnum()) { + if (methodParameterCount == parameterAnnotations.length + 2 && + sym.type == methodDescriptor) { + //handle constructors of enum types without the Signature attribute - + //there are the two synthetic parameters (name and ordinal) in the + //constructor, but there may be only parameter annotations for the + //real non-synthetic parameters: + ParameterAnnotations[] newParameterAnnotations = new ParameterAnnotations[parameterAnnotations.length + 2]; + System.arraycopy(parameterAnnotations, 0, newParameterAnnotations, 2, parameterAnnotations.length); + parameterAnnotations = newParameterAnnotations; + return ; + } + } else if (sym.owner.isDirectlyOrIndirectlyLocal() || forceLocal) { + //local class may capture the enclosing instance (as the first parameter), + //and local variables (as trailing parameters) + //if there are less parameter annotations than parameters, put the existing + //ones starting with offset: + if (methodParameterCount > parameterAnnotations.length && + sym.type == methodDescriptor) { + ParameterAnnotations[] newParameterAnnotations = new ParameterAnnotations[methodParameterCount]; + System.arraycopy(parameterAnnotations, 0, newParameterAnnotations, 1, parameterAnnotations.length); + parameterAnnotations = newParameterAnnotations; + return ; + } + } + + //no heuristics worked, drop the annotations: + dropParameterAnnotations(); + } + + private void dropParameterAnnotations() { + parameterAnnotations = null; + if (lintClassfile) { + log.warning(LintCategory.CLASSFILE, Warnings.RuntimeInvisibleParameterAnnotations(currentClassFile)); + } + } /** * Creates the parameter at the position {@code mpIndex} in the parameter list of the owning method. * Flags are optionally read from the MethodParameters attribute. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 7e41f43aeb2..a991ae60601 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2547,8 +2547,17 @@ compiler.misc.bad.enclosing.class=\ compiler.misc.bad.enclosing.method=\ bad enclosing method attribute for class {0} -compiler.misc.bad.runtime.invisible.param.annotations=\ - bad RuntimeInvisibleParameterAnnotations attribute: {0} +# 0: file name +compiler.warn.runtime.visible.invisible.param.annotations.mismatch=\ + the length of parameters in RuntimeVisibleParameterAnnotations attribute and \ + RuntimeInvisibleParameterAnnotations attribute in: {0} \ + do not match, ignoring both attributes + +# 0: file name +compiler.warn.runtime.invisible.parameter.annotations=\ + the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes \ + in: {0} \ + cannot be mapped to the method''s parameters compiler.misc.bad.const.pool.tag=\ bad constant pool tag: {0} diff --git a/src/jdk.hotspot.agent/doc/index.html b/src/jdk.hotspot.agent/doc/index.html index 9a67ad1bf77..2e3ba38e4b8 100644 --- a/src/jdk.hotspot.agent/doc/index.html +++ b/src/jdk.hotspot.agent/doc/index.html @@ -21,8 +21,9 @@

          SA Modes

          • attaching to a local process
          • opening a core file -
          • attaching to a remote "debug server" +
          • attaching to a remote "debug server" (deprecated)
          +

          WARNING: jhsdb debugd is deprecated and will be removed in a future release.

          The remote case requires running the debug server on the remote machine. This is done by running "jhsdb debugd", and also adding arguments specifying the core diff --git a/src/jdk.hotspot.agent/doc/transported_core.html b/src/jdk.hotspot.agent/doc/transported_core.html index 7d8b2804d0a..9f932d9827f 100644 --- a/src/jdk.hotspot.agent/doc/transported_core.html +++ b/src/jdk.hotspot.agent/doc/transported_core.html @@ -21,6 +21,7 @@

          Debugging transported core dumps

          it was produced on. This is done by first running jhsdb debugd on the machine with the core dump, and then attaching to it from another machine by using the jhsdb --connect argument. See the jhsdb man page for details. +

          WARNING: jhsdb debugd is deprecated and will be removed in a future release.

        diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/DebugServer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/DebugServer.java index 220267acf90..2813a58c94d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/DebugServer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/DebugServer.java @@ -28,6 +28,7 @@ import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.oops.*; +@Deprecated(since="24", forRemoval=true) public class DebugServer { private void usage() { System.out.println("usage: java " + getClass().getName() + " [server id]"); @@ -42,9 +43,11 @@ private void usage() { } public static void main(String[] args) { + System.err.println("WARNING: DebugServer is deprecated and will be removed in a future release."); new DebugServer().run(args); } + @SuppressWarnings("removal") private void run(String[] args) { if ((args.length < 1) || (args.length > 3)) { usage(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java index 71ed978199c..b9990828624 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java @@ -204,6 +204,7 @@ public synchronized boolean detach() throws DebuggerException { specific debuggee on the server. Allows to specify the port number to which the RMI connector is bound. If not specified a random available port is used. */ + @Deprecated(since="24", forRemoval=true) public synchronized void startServer(int processID, String serverID, String serverName, @@ -224,6 +225,7 @@ public synchronized void startServer(int processID, starts a debug server, allowing remote machines to connect and examine this process. Uses specified name to uniquely identify a specific debuggee on the server */ + @Deprecated(since="24", forRemoval=true) public synchronized void startServer(int processID, String serverID, String serverName) { startServer(processID, serverID, serverName, 0); } @@ -231,6 +233,7 @@ public synchronized void startServer(int processID, String serverID, String serv /** This attaches to a process running on the local machine and starts a debug server, allowing remote machines to connect and examine this process. */ + @Deprecated(since="24", forRemoval=true) public synchronized void startServer(int processID) throws DebuggerException { startServer(processID, null, null); @@ -241,6 +244,7 @@ public synchronized void startServer(int processID) core file. Uses supplied uniqueID to uniquely identify a specific debuggee. Allows to specify the port number to which the RMI connector is bound. If not specified a random available port is used. */ + @Deprecated(since="24", forRemoval=true) public synchronized void startServer(String javaExecutableName, String coreFileName, String serverID, @@ -266,6 +270,7 @@ public synchronized void startServer(String javaExecutableName, server, allowing remote machines to connect and examine this core file. Uses supplied uniqueID to uniquely identify a specific debuggee */ + @Deprecated(since="24", forRemoval=true) public synchronized void startServer(String javaExecutableName, String coreFileName, String serverID, @@ -276,6 +281,7 @@ public synchronized void startServer(String javaExecutableName, /** This opens a core file on the local machine and starts a debug server, allowing remote machines to connect and examine this core file. */ + @Deprecated(since="24", forRemoval=true) public synchronized void startServer(String javaExecutableName, String coreFileName) throws DebuggerException { startServer(javaExecutableName, coreFileName, null, null); @@ -283,6 +289,7 @@ public synchronized void startServer(String javaExecutableName, String coreFileN /** This may only be called on the server side after startServer() has been called */ + @Deprecated(since="24", forRemoval=true) public synchronized boolean shutdownServer() throws DebuggerException { if (!isServer) { throw new DebuggerException("Should not call shutdownServer() for client configuration"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java index b884058a3a2..cac3f0a1f61 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java @@ -43,7 +43,7 @@ public class SALauncher { private static boolean launcherHelp() { System.out.println(" clhsdb \tcommand line debugger"); System.out.println(" hsdb \tui debugger"); - System.out.println(" debugd --help\tto get more information"); + System.out.println(" debugd --help\tto get more information (deprecated)"); System.out.println(" jstack --help\tto get more information"); System.out.println(" jmap --help\tto get more information"); System.out.println(" jinfo --help\tto get more information"); @@ -71,12 +71,14 @@ private static boolean commonHelp(String mode, boolean canConnectToRemote) { System.out.println(" --connect [@][:registryport][/servername] To connect to a remote debug server (debugd)."); } System.out.println(); + if (canConnectToRemote) { + System.out.println(" The --connect option is deprecated and will be removed in a future release."); + } System.out.println(" The --core and --exe options must be set together to give the core"); System.out.println(" file, and associated executable, to operate on. They can use"); System.out.println(" absolute or relative paths."); System.out.println(" The --pid option can be set to operate on a live process."); if (canConnectToRemote) { - System.out.println(" The --connect option can be set to connect to a debug server (debugd)."); System.out.println(" --core, --pid, and --connect are mutually exclusive."); } else { System.out.println(" --core and --pid are mutually exclusive."); @@ -91,6 +93,7 @@ private static boolean commonHelp(String mode, boolean canConnectToRemote) { } private static boolean debugdHelp() { + System.out.println("WARNING: debugd is deprecated and will be removed in a future release."); System.out.println(" --serverid A unique identifier for this debugd server."); System.out.println(" --servername Instance name of debugd server."); System.out.println(" --rmiport Sets the port number to which the RMI connector is bound." + @@ -213,6 +216,7 @@ private static String[] buildAttachArgs(Map newArgMap, newArgs.add(core); } else if (connect != NO_REMOTE) { + System.err.println("WARNING: --connect is deprecated and will be removed in a future release."); newArgs.add(connect); } @@ -361,7 +365,10 @@ private static void runJSNAP(String[] oldArgs) { JSnap.main(buildAttachArgs(newArgMap, false)); } + @SuppressWarnings("removal") private static void runDEBUGD(String[] args) { + System.err.println("WARNING: debugd is deprecated and will be removed in a future release."); + // By default SA agent classes prefer Windows process debugger // to windbg debugger. SA expects special properties to be set // to choose other debuggers. We will set those here before diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java index 67e799b2712..90e4b5b98b4 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java @@ -143,6 +143,8 @@ public ImmutableOopMapSet getOopMaps() { public boolean isRuntimeStub() { return false; } + public boolean isUpcallStub() { return false; } + public boolean isDeoptimizationStub() { return false; } public boolean isUncommonTrapStub() { return false; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java index 448372e2a36..e2eac930e02 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -60,6 +60,7 @@ private static synchronized void initialize(TypeDataBase db) { virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class); virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class); virtualConstructor.addMapping("VtableBlob", VtableBlob.class); + virtualConstructor.addMapping("UpcallStub", UpcallStub.class); virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class); virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class); if (VM.getVM().isServerCompiler()) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java new file mode 100644 index 00000000000..4e324ba38e4 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/UpcallStub.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.code; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +public class UpcallStub extends RuntimeBlob { + + private static CIntegerField frameDataOffsetField; + private static AddressField lastJavaFPField; + private static AddressField lastJavaSPField; + private static AddressField lastJavaPCField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + Type type = db.lookupType("UpcallStub"); + frameDataOffsetField = type.getCIntegerField("_frame_data_offset"); + + Type anchorType = db.lookupType("JavaFrameAnchor"); + lastJavaSPField = anchorType.getAddressField("_last_Java_sp"); + lastJavaPCField = anchorType.getAddressField("_last_Java_pc"); + + try { + lastJavaFPField = anchorType.getAddressField("_last_Java_fp"); + } catch (Exception e) { + // Some platforms (e.g. PPC64) does not have this field. + lastJavaFPField = null; + } + } + + public UpcallStub(Address addr) { + super(addr); + } + + protected Address getJavaFrameAnchor(Frame frame) { + var frameDataOffset = frameDataOffsetField.getValue(addr); + var frameDataAddr = frame.getUnextendedSP().addOffsetTo(frameDataOffset); + var frameData = VMObjectFactory.newObject(FrameData.class, frameDataAddr); + return frameData.getJavaFrameAnchor(); + } + + public Address getLastJavaSP(Frame frame) { + return lastJavaSPField.getValue(getJavaFrameAnchor(frame)); + } + + public Address getLastJavaFP(Frame frame) { + return lastJavaFPField == null ? null : lastJavaFPField.getValue(getJavaFrameAnchor(frame)); + } + + public Address getLastJavaPC(Frame frame) { + return lastJavaPCField.getValue(getJavaFrameAnchor(frame)); + } + + public boolean isUpcallStub() { + return true; + } + + public static class FrameData extends VMObject { + + private static AddressField jfaField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + Type type = db.lookupType("UpcallStub::FrameData"); + jfaField = type.getAddressField("jfa"); + } + + public FrameData(Address addr) { + super(addr); + } + + public Address getJavaFrameAnchor() { + return addr.addOffsetTo(jfaField.getOffset()); + } + + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index 5d8712002f8..dca5f2efa3b 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -292,7 +292,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) { } if (cb != null) { - return senderForCompiledFrame(map, cb); + return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb); } // Must be native-compiled frame, i.e. the marshaling code for native @@ -327,6 +327,34 @@ private Frame senderForEntryFrame(AARCH64RegisterMap map) { return fr; } + private Frame senderForUpcallStub(AARCH64RegisterMap map, UpcallStub stub) { + if (DEBUG) { + System.out.println("senderForUpcallStub"); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + var lastJavaFP = stub.getLastJavaFP(this); + var lastJavaSP = stub.getLastJavaSP(this); + var lastJavaPC = stub.getLastJavaPC(this); + + if (Assert.ASSERTS_ENABLED) { + Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack"); + } + AARCH64Frame fr; + if (lastJavaPC != null) { + fr = new AARCH64Frame(lastJavaSP, lastJavaFP, lastJavaPC); + } else { + fr = new AARCH64Frame(lastJavaSP, lastJavaFP); + } + map.clear(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); + } + return fr; + } + //------------------------------------------------------------------------------ // frame::adjust_unextended_sp private void adjustUnextendedSP() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java index 710f30f19f2..224206ee6fe 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 @@ -279,7 +279,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) { } if (cb != null) { - return senderForCompiledFrame(map, cb); + return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb); } // Must be native-compiled frame, i.e. the marshaling code for native @@ -314,6 +314,34 @@ private Frame senderForEntryFrame(PPC64RegisterMap map) { return fr; } + private Frame senderForUpcallStub(PPC64RegisterMap map, UpcallStub stub) { + if (DEBUG) { + System.out.println("senderForUpcallStub"); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + var lastJavaFP = stub.getLastJavaFP(this); // This will be null + var lastJavaSP = stub.getLastJavaSP(this); + var lastJavaPC = stub.getLastJavaPC(this); + + if (Assert.ASSERTS_ENABLED) { + Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack"); + } + PPC64Frame fr; + if (lastJavaPC != null) { + fr = new PPC64Frame(lastJavaSP, lastJavaFP, lastJavaPC); + } else { + fr = new PPC64Frame(lastJavaSP, lastJavaFP); + } + map.clear(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); + } + return fr; + } + //------------------------------------------------------------------------------ // frame::adjust_unextended_sp private void adjustUnextendedSP() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java index c8e503db93b..948a3008016 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * Copyright (c) 2021, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -284,7 +284,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) { } if (cb != null) { - return senderForCompiledFrame(map, cb); + return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb); } // Must be native-compiled frame, i.e. the marshaling code for native @@ -319,6 +319,34 @@ private Frame senderForEntryFrame(RISCV64RegisterMap map) { return fr; } + private Frame senderForUpcallStub(RISCV64RegisterMap map, UpcallStub stub) { + if (DEBUG) { + System.out.println("senderForUpcallStub"); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + var lastJavaFP = stub.getLastJavaFP(this); + var lastJavaSP = stub.getLastJavaSP(this); + var lastJavaPC = stub.getLastJavaPC(this); + + if (Assert.ASSERTS_ENABLED) { + Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack"); + } + RISCV64Frame fr; + if (lastJavaPC != null) { + fr = new RISCV64Frame(lastJavaSP, lastJavaFP, lastJavaPC); + } else { + fr = new RISCV64Frame(lastJavaSP, lastJavaFP); + } + map.clear(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); + } + return fr; + } + //------------------------------------------------------------------------------ // frame::adjust_unextended_sp private void adjustUnextendedSP() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java index 1ffc9761a33..169ecea1565 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -289,7 +289,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) { } if (cb != null) { - return senderForCompiledFrame(map, cb); + return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb); } // Must be native-compiled frame, i.e. the marshaling code for native @@ -324,6 +324,34 @@ private Frame senderForEntryFrame(X86RegisterMap map) { return fr; } + private Frame senderForUpcallStub(X86RegisterMap map, UpcallStub stub) { + if (DEBUG) { + System.out.println("senderForUpcallStub"); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + var lastJavaFP = stub.getLastJavaFP(this); + var lastJavaSP = stub.getLastJavaSP(this); + var lastJavaPC = stub.getLastJavaPC(this); + + if (Assert.ASSERTS_ENABLED) { + Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack"); + } + X86Frame fr; + if (lastJavaPC != null) { + fr = new X86Frame(lastJavaSP, lastJavaFP, lastJavaPC); + } else { + fr = new X86Frame(lastJavaSP, lastJavaFP); + } + map.clear(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); + } + return fr; + } + //------------------------------------------------------------------------------ // frame::adjust_unextended_sp private void adjustUnextendedSP() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java index a889d10fb43..02a389d08b2 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java index 7f07c32ab13..4e035b13b5e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java index 20bf261999a..15dd06cdccc 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java index 2756128b469..6ac9d7a8918 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java index c2f5e6f85a9..ed6e15ca293 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java index 385fbba55a3..f2a077604f7 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -512,7 +512,7 @@ public long laneHelper(int i) { this, i, (vec, ix) -> { double[] vecarr = vec.vec(); - return (long)Double.doubleToLongBits(vecarr[ix]); + return (long)Double.doubleToRawLongBits(vecarr[ix]); }); } @@ -529,7 +529,7 @@ public Double128Vector withLane(int i, double e) { public Double128Vector withLaneHelper(int i, double e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Double.doubleToLongBits(e), + this, i, (long)Double.doubleToRawLongBits(e), (v, ix, bits) -> { double[] res = v.vec().clone(); res[ix] = Double.longBitsToDouble((long)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java index e73ada8a088..da9dd421b17 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -514,7 +514,7 @@ public long laneHelper(int i) { this, i, (vec, ix) -> { double[] vecarr = vec.vec(); - return (long)Double.doubleToLongBits(vecarr[ix]); + return (long)Double.doubleToRawLongBits(vecarr[ix]); }); } @@ -533,7 +533,7 @@ public Double256Vector withLane(int i, double e) { public Double256Vector withLaneHelper(int i, double e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Double.doubleToLongBits(e), + this, i, (long)Double.doubleToRawLongBits(e), (v, ix, bits) -> { double[] res = v.vec().clone(); res[ix] = Double.longBitsToDouble((long)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java index 5f239d2a527..d23f09e774b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -518,7 +518,7 @@ public long laneHelper(int i) { this, i, (vec, ix) -> { double[] vecarr = vec.vec(); - return (long)Double.doubleToLongBits(vecarr[ix]); + return (long)Double.doubleToRawLongBits(vecarr[ix]); }); } @@ -541,7 +541,7 @@ public Double512Vector withLane(int i, double e) { public Double512Vector withLaneHelper(int i, double e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Double.doubleToLongBits(e), + this, i, (long)Double.doubleToRawLongBits(e), (v, ix, bits) -> { double[] res = v.vec().clone(); res[ix] = Double.longBitsToDouble((long)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java index cd5f14c47db..19bd640f978 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -511,7 +511,7 @@ public long laneHelper(int i) { this, i, (vec, ix) -> { double[] vecarr = vec.vec(); - return (long)Double.doubleToLongBits(vecarr[ix]); + return (long)Double.doubleToRawLongBits(vecarr[ix]); }); } @@ -527,7 +527,7 @@ public Double64Vector withLane(int i, double e) { public Double64Vector withLaneHelper(int i, double e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Double.doubleToLongBits(e), + this, i, (long)Double.doubleToRawLongBits(e), (v, ix, bits) -> { double[] res = v.vec().clone(); res[ix] = Double.longBitsToDouble((long)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java index 84b0b240ca5..73f6f2ece5d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -510,7 +510,7 @@ public long laneHelper(int i) { this, i, (vec, ix) -> { double[] vecarr = vec.vec(); - return (long)Double.doubleToLongBits(vecarr[ix]); + return (long)Double.doubleToRawLongBits(vecarr[ix]); }); } @@ -526,7 +526,7 @@ public DoubleMaxVector withLane(int i, double e) { public DoubleMaxVector withLaneHelper(int i, double e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Double.doubleToLongBits(e), + this, i, (long)Double.doubleToRawLongBits(e), (v, ix, bits) -> { double[] res = v.vec().clone(); res[ix] = Double.longBitsToDouble((long)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java index d6b66f77431..ae47beca5de 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -514,7 +514,7 @@ public int laneHelper(int i) { this, i, (vec, ix) -> { float[] vecarr = vec.vec(); - return (long)Float.floatToIntBits(vecarr[ix]); + return (long)Float.floatToRawIntBits(vecarr[ix]); }); } @@ -533,7 +533,7 @@ public Float128Vector withLane(int i, float e) { public Float128Vector withLaneHelper(int i, float e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Float.floatToIntBits(e), + this, i, (long)Float.floatToRawIntBits(e), (v, ix, bits) -> { float[] res = v.vec().clone(); res[ix] = Float.intBitsToFloat((int)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java index 38e5bee8a97..d5c0506a542 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -518,7 +518,7 @@ public int laneHelper(int i) { this, i, (vec, ix) -> { float[] vecarr = vec.vec(); - return (long)Float.floatToIntBits(vecarr[ix]); + return (long)Float.floatToRawIntBits(vecarr[ix]); }); } @@ -541,7 +541,7 @@ public Float256Vector withLane(int i, float e) { public Float256Vector withLaneHelper(int i, float e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Float.floatToIntBits(e), + this, i, (long)Float.floatToRawIntBits(e), (v, ix, bits) -> { float[] res = v.vec().clone(); res[ix] = Float.intBitsToFloat((int)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java index 3a398976d98..536f7db6946 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -526,7 +526,7 @@ public int laneHelper(int i) { this, i, (vec, ix) -> { float[] vecarr = vec.vec(); - return (long)Float.floatToIntBits(vecarr[ix]); + return (long)Float.floatToRawIntBits(vecarr[ix]); }); } @@ -557,7 +557,7 @@ public Float512Vector withLane(int i, float e) { public Float512Vector withLaneHelper(int i, float e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Float.floatToIntBits(e), + this, i, (long)Float.floatToRawIntBits(e), (v, ix, bits) -> { float[] res = v.vec().clone(); res[ix] = Float.intBitsToFloat((int)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java index 867b3e284ae..849062c6cb8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -512,7 +512,7 @@ public int laneHelper(int i) { this, i, (vec, ix) -> { float[] vecarr = vec.vec(); - return (long)Float.floatToIntBits(vecarr[ix]); + return (long)Float.floatToRawIntBits(vecarr[ix]); }); } @@ -529,7 +529,7 @@ public Float64Vector withLane(int i, float e) { public Float64Vector withLaneHelper(int i, float e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Float.floatToIntBits(e), + this, i, (long)Float.floatToRawIntBits(e), (v, ix, bits) -> { float[] res = v.vec().clone(); res[ix] = Float.intBitsToFloat((int)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java index 242d405eafb..b14797f6788 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -510,7 +510,7 @@ public int laneHelper(int i) { this, i, (vec, ix) -> { float[] vecarr = vec.vec(); - return (long)Float.floatToIntBits(vecarr[ix]); + return (long)Float.floatToRawIntBits(vecarr[ix]); }); } @@ -526,7 +526,7 @@ public FloatMaxVector withLane(int i, float e) { public FloatMaxVector withLaneHelper(int i, float e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)Float.floatToIntBits(e), + this, i, (long)Float.floatToRawIntBits(e), (v, ix, bits) -> { float[] res = v.vec().clone(); res[ix] = Float.intBitsToFloat((int)bits); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java index 0c83b037454..cd652941fb3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java index abb10696ba4..b76a1035561 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java index 7b6435e4c0a..3a42c661144 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java index 491010be90e..4181e6b4ea3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java index e20829f7c4f..785022fcd65 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java index cf552c23a80..302c71bc13b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java index ffa1029bdd8..04c51c377e1 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java index aea8fe0fe6c..fbcd57400d5 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java index ffb07535d65..3b2e77f1a54 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java index e4197cb7f2e..cc3641be3d6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java index 3930826aa09..7703df9a59a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java index e39e89f6137..cf845930195 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java index 1caea78f748..67a5073df05 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java index 640be746f15..263ee10d907 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java index 96683ac53c4..07a2caebef0 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template index cebdc7594d6..111d4bbefd4 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -561,7 +561,7 @@ final class $vectortype$ extends $abstractvectortype$ { this, i, (vec, ix) -> { $type$[] vecarr = vec.vec(); - return (long)$Type$.$type$To$Bitstype$Bits(vecarr[ix]); + return (long)$Type$.$type$ToRaw$Bitstype$Bits(vecarr[ix]); }); } @@ -607,7 +607,7 @@ final class $vectortype$ extends $abstractvectortype$ { public $vectortype$ withLaneHelper(int i, $type$ e) { return VectorSupport.insert( VCLASS, ETYPE, VLENGTH, - this, i, (long)$Type$.$type$To$Bitstype$Bits(e), + this, i, (long)$Type$.$type$ToRaw$Bitstype$Bits(e), (v, ix, bits) -> { $type$[] res = v.vec().clone(); res[ix] = $Type$.$bitstype$BitsTo$Type$(($bitstype$)bits); diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 6163ef82647..551568ca86f 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, 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 @@ -251,7 +251,7 @@ private static File createTempFileInSameDirectoryAs(File file) * Starts main program with the specified arguments. */ @SuppressWarnings({"removal"}) - public synchronized boolean run(String args[]) { + public synchronized boolean run(String[] args) { ok = true; if (!parseArgs(args)) { return false; @@ -366,11 +366,9 @@ public synchronized boolean run(String args[]) { if (fname != null) { list(fname, files); } else { - InputStream in = new FileInputStream(FileDescriptor.in); - try { - list(new BufferedInputStream(in), files); - } finally { - in.close(); + try (InputStream in = new FileInputStream(FileDescriptor.in); + BufferedInputStream bis = new BufferedInputStream(in)) { + list(bis, files); } } } else if (xflag) { @@ -386,18 +384,12 @@ public synchronized boolean run(String args[]) { // latter can handle it. String[] files = filesMapToFiles(filesMap); - if (fname != null && files != null) { + if (fname != null) { extract(fname, files); } else { - InputStream in = (fname == null) - ? new FileInputStream(FileDescriptor.in) - : new FileInputStream(fname); - try { - if (!extract(new BufferedInputStream(in), files) && fname != null) { - extract(fname, files); - } - } finally { - in.close(); + try (InputStream in = new FileInputStream(FileDescriptor.in); + BufferedInputStream bis = new BufferedInputStream(in)) { + extract(bis, files); } } } else if (iflag) { @@ -503,7 +495,7 @@ Stream filesToEntryNames(Map.Entry fileEntries) { /** * Parses command line arguments. */ - boolean parseArgs(String args[]) { + boolean parseArgs(String[] args) { /* Preprocess and expand @file arguments */ try { args = CommandLine.parse(args); @@ -935,118 +927,116 @@ boolean update(InputStream in, OutputStream out, Map moduleInfos, JarIndex jarIndex) throws IOException { - ZipInputStream zis = new ZipInputStream(in); - ZipOutputStream zos = new JarOutputStream(out); - ZipEntry e = null; - boolean foundManifest = false; boolean updateOk = true; + try (ZipInputStream zis = new ZipInputStream(in); + ZipOutputStream zos = new JarOutputStream(out)) { - // All actual entries added/updated/existing, in the jar file (excl manifest - // and module-info.class ). - Set jentries = new HashSet<>(); - - if (jarIndex != null) { - addIndex(jarIndex, zos); - } + if (jarIndex != null) { + addIndex(jarIndex, zos); + } + ZipEntry e = null; + boolean foundManifest = false; + // All actual entries added/updated/existing, in the jar file (excl manifest + // and module-info.class ). + Set jentries = new HashSet<>(); - // put the old entries first, replace if necessary - while ((e = zis.getNextEntry()) != null) { - String name = e.getName(); + // put the old entries first, replace if necessary + while ((e = zis.getNextEntry()) != null) { + String name = e.getName(); - boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME); - boolean isModuleInfoEntry = isModuleInfoEntry(name); + boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME); + boolean isModuleInfoEntry = isModuleInfoEntry(name); - if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME)) - || (Mflag && isManifestEntry)) { - continue; - } else if (isManifestEntry && ((newManifest != null) || + if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME)) + || (Mflag && isManifestEntry)) { + continue; + } else if (isManifestEntry && ((newManifest != null) || (ename != null) || isMultiRelease)) { - foundManifest = true; - if (newManifest != null) { - // Don't read from the newManifest InputStream, as we - // might need it below, and we can't re-read the same data - // twice. - try (FileInputStream fis = new FileInputStream(mname)) { - if (isAmbiguousMainClass(new Manifest(fis))) { - return false; + foundManifest = true; + if (newManifest != null) { + // Don't read from the newManifest InputStream, as we + // might need it below, and we can't re-read the same data + // twice. + try (FileInputStream fis = new FileInputStream(mname)) { + if (isAmbiguousMainClass(new Manifest(fis))) { + return false; + } } } - } - // Update the manifest. - Manifest old = new Manifest(zis); - if (newManifest != null) { - old.read(newManifest); - } - if (!updateManifest(old, zos)) { - return false; - } - } else if (moduleInfos != null && isModuleInfoEntry) { - moduleInfos.putIfAbsent(name, new StreamedModuleInfoEntry(name, zis.readAllBytes(), e.getLastModifiedTime())); - } else { - boolean isDir = e.isDirectory(); - if (!entryMap.containsKey(name)) { // copy the old stuff - // do our own compression - ZipEntry e2 = new ZipEntry(name); - e2.setMethod(e.getMethod()); - setZipEntryTime(e2, e.getTime()); - e2.setComment(e.getComment()); - e2.setExtra(e.getExtra()); - if (e.getMethod() == ZipEntry.STORED) { - e2.setSize(e.getSize()); - e2.setCrc(e.getCrc()); + // Update the manifest. + Manifest old = new Manifest(zis); + if (newManifest != null) { + old.read(newManifest); + } + if (!updateManifest(old, zos)) { + return false; + } + } else if (moduleInfos != null && isModuleInfoEntry) { + moduleInfos.putIfAbsent(name, new StreamedModuleInfoEntry(name, zis.readAllBytes(), e.getLastModifiedTime())); + } else { + boolean isDir = e.isDirectory(); + if (!entryMap.containsKey(name)) { // copy the old stuff + // do our own compression + ZipEntry e2 = new ZipEntry(name); + e2.setMethod(e.getMethod()); + setZipEntryTime(e2, e.getTime()); + e2.setComment(e.getComment()); + e2.setExtra(e.getExtra()); + if (e.getMethod() == ZipEntry.STORED) { + e2.setSize(e.getSize()); + e2.setCrc(e.getCrc()); + } + zos.putNextEntry(e2); + copy(zis, zos); + } else { // replace with the new files + Entry ent = entryMap.get(name); + addFile(zos, ent); + entryMap.remove(name); + entries.remove(ent); + isDir = ent.isDir; + } + if (!isDir) { + jentries.add(name); } - zos.putNextEntry(e2); - copy(zis, zos); - } else { // replace with the new files - Entry ent = entryMap.get(name); - addFile(zos, ent); - entryMap.remove(name); - entries.remove(ent); - isDir = ent.isDir; - } - if (!isDir) { - jentries.add(name); } } - } - // add the remaining new files - for (Entry entry : entries) { - addFile(zos, entry); - if (!entry.isDir) { - jentries.add(entry.name); + // add the remaining new files + for (Entry entry : entries) { + addFile(zos, entry); + if (!entry.isDir) { + jentries.add(entry.name); + } } - } - if (!foundManifest) { - if (newManifest != null) { - Manifest m = new Manifest(newManifest); - updateOk = !isAmbiguousMainClass(m); - if (updateOk) { - if (!updateManifest(m, zos)) { + if (!foundManifest) { + if (newManifest != null) { + Manifest m = new Manifest(newManifest); + updateOk = !isAmbiguousMainClass(m); + if (updateOk) { + if (!updateManifest(m, zos)) { + updateOk = false; + } + } + } else if (ename != null) { + if (!updateManifest(new Manifest(), zos)) { updateOk = false; } } - } else if (ename != null) { - if (!updateManifest(new Manifest(), zos)) { + } + if (updateOk) { + if (moduleInfos != null && !moduleInfos.isEmpty()) { + Set pkgs = new HashSet<>(); + jentries.forEach(je -> addPackageIfNamed(pkgs, je)); + addExtendedModuleAttributes(moduleInfos, pkgs); + updateOk = checkModuleInfo(moduleInfos.get(MODULE_INFO), jentries); + updateModuleInfo(moduleInfos, zos); + // TODO: check manifest main classes, etc + } else if (moduleVersion != null || modulesToHash != null) { + error(getMsg("error.module.options.without.info")); updateOk = false; } } } - if (updateOk) { - if (moduleInfos != null && !moduleInfos.isEmpty()) { - Set pkgs = new HashSet<>(); - jentries.forEach( je -> addPackageIfNamed(pkgs, je)); - addExtendedModuleAttributes(moduleInfos, pkgs); - updateOk = checkModuleInfo(moduleInfos.get(MODULE_INFO), jentries); - updateModuleInfo(moduleInfos, zos); - // TODO: check manifest main classes, etc - } else if (moduleVersion != null || modulesToHash != null) { - error(getMsg("error.module.options.without.info")); - updateOk = false; - } - } - zis.close(); - zos.close(); return updateOk; } @@ -1374,19 +1364,12 @@ void updateLastModifiedTime(Set zes) throws IOException { /** * Extracts specified entries from JAR file. - * - * @return whether entries were found and successfully extracted - * (indicating this was a zip file without "leading garbage") */ - boolean extract(InputStream in, String files[]) throws IOException { + void extract(InputStream in, String[] files) throws IOException { ZipInputStream zis = new ZipInputStream(in); ZipEntry e; - // Set of all directory entries specified in archive. Disallows - // null entries. Disallows all entries if using pre-6.0 behavior. - boolean entriesFound = false; Set dirs = newDirSet(); while ((e = zis.getNextEntry()) != null) { - entriesFound = true; if (files == null) { dirs.add(extractFile(zis, e)); } else { @@ -1405,32 +1388,31 @@ boolean extract(InputStream in, String files[]) throws IOException { // instead of during, because creating a file in a directory changes // that directory's timestamp. updateLastModifiedTime(dirs); - - return entriesFound; } /** * Extracts specified entries from JAR file, via ZipFile. */ - void extract(String fname, String files[]) throws IOException { - ZipFile zf = new ZipFile(fname); - Set dirs = newDirSet(); - Enumeration zes = zf.entries(); - while (zes.hasMoreElements()) { - ZipEntry e = zes.nextElement(); - if (files == null) { - dirs.add(extractFile(zf.getInputStream(e), e)); - } else { - String name = e.getName(); - for (String file : files) { - if (name.startsWith(file)) { - dirs.add(extractFile(zf.getInputStream(e), e)); - break; + void extract(String fname, String[] files) throws IOException { + final Set dirs; + try (ZipFile zf = new ZipFile(fname)) { + dirs = newDirSet(); + Enumeration zes = zf.entries(); + while (zes.hasMoreElements()) { + ZipEntry e = zes.nextElement(); + if (files == null) { + dirs.add(extractFile(zf.getInputStream(e), e)); + } else { + String name = e.getName(); + for (String file : files) { + if (name.startsWith(file)) { + dirs.add(extractFile(zf.getInputStream(e), e)); + break; + } } } } } - zf.close(); updateLastModifiedTime(dirs); } @@ -1505,7 +1487,7 @@ ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException { /** * Lists contents of JAR file. */ - void list(InputStream in, String files[]) throws IOException { + void list(InputStream in, String[] files) throws IOException { ZipInputStream zis = new ZipInputStream(in); ZipEntry e; while ((e = zis.getNextEntry()) != null) { @@ -1523,13 +1505,13 @@ void list(InputStream in, String files[]) throws IOException { /** * Lists contents of JAR file, via ZipFile. */ - void list(String fname, String files[]) throws IOException { - ZipFile zf = new ZipFile(fname); - Enumeration zes = zf.entries(); - while (zes.hasMoreElements()) { - printEntry(zes.nextElement(), files); + void list(String fname, String[] files) throws IOException { + try (ZipFile zf = new ZipFile(fname)) { + Enumeration zes = zf.entries(); + while (zes.hasMoreElements()) { + printEntry(zes.nextElement(), files); + } } - zf.close(); } /** @@ -1572,10 +1554,8 @@ List getJarPath(String jar) throws IOException { // class path attribute will give us jar file name with // '/' as separators, so we need to change them to the // appropriate one before we open the jar file. - JarFile rf = new JarFile(jar.replace('/', File.separatorChar)); - - if (rf != null) { - Manifest man = rf.getManifest(); + try (JarFile jarFile = new JarFile(jar.replace('/', File.separatorChar))) { + Manifest man = jarFile.getManifest(); if (man != null) { Attributes attr = man.getMainAttributes(); if (attr != null) { @@ -1596,7 +1576,6 @@ List getJarPath(String jar) throws IOException { } } } - rf.close(); return files; } @@ -1703,7 +1682,7 @@ void warn(String s) { /** * Main routine to start program. */ - public static void main(String args[]) { + public static void main(String[] args) { Main jartool = new Main(System.out, System.err, "jar"); System.exit(jartool.run(args) ? 0 : 1); } 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 84672926cf8..7efaec87692 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 @@ -109,7 +109,7 @@ protected Content getSummaryLink(Element member) { } String signature = utils.flatSignature((ExecutableElement) member, typeElement); if (signature.length() > 2) { - content.add(new HtmlTree(HtmlTag.WBR)); + content.add(HtmlTree.WBR()); } content.add(signature); @@ -144,7 +144,7 @@ protected void addTypeParameters(ExecutableElement member, Content target) { // Add explicit line break between method type parameters and // return type in member summary table to avoid random wrapping. if (typeParameters.charCount() > 10) { - target.add(new HtmlTree(HtmlTag.BR)); + target.add(HtmlTree.BR()); } else { target.add(Entity.NO_BREAK_SPACE); } @@ -233,7 +233,7 @@ protected void addParameters(ExecutableElement member, Content target) { Content params = getParameters(member, false); if (params.charCount() > 2) { // only add for non-empty parameters - target.add(new HtmlTree(HtmlTag.WBR)); + target.add(HtmlTree.WBR()); } target.add(params); } 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 e2b81bb3982..59a8f589230 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 @@ -451,7 +451,7 @@ protected abstract void addInheritedSummaryLink(TypeElement typeElement, */ protected void addModifiersAndType(Element member, TypeMirror type, Content target) { - var code = new HtmlTree(HtmlTag.CODE); + var code = HtmlTree.CODE(); addModifiers(member, code); if (type == null) { code.add(switch (member.getKind()) { @@ -670,7 +670,7 @@ public Content getInheritedSummaryHeader(TypeElement tElement) { * @return the inherited summary links */ public Content getInheritedSummaryLinks() { - return new HtmlTree(HtmlTag.CODE); + return HtmlTree.CODE(); } /** 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 594132743eb..915dbd7627a 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 @@ -79,10 +79,9 @@ protected AbstractTreeWriter(HtmlConfiguration configuration, protected void addLevelInfo(TypeElement parent, Collection collection, Hierarchy hierarchy, Content content) { if (!collection.isEmpty()) { - var ul = new HtmlTree(HtmlTag.UL); + var ul = HtmlTree.UL(); for (TypeElement local : collection) { - var li = new HtmlTree(HtmlTag.LI); - li.setStyle(HtmlStyles.circle); + var li = HtmlTree.LI(HtmlStyles.circle); addPartialInfo(local, li); addExtendsImplements(parent, local, li); addLevelInfo(local, hierarchy.subtypes(local), hierarchy, li); // Recurse 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 ac953dccb55..d10478fb3ba 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 @@ -423,7 +423,7 @@ protected HtmlTree getClassUseHeader() { HtmlTree body = getBody(getWindowTitle(title)); ContentBuilder headingContent = new ContentBuilder(); headingContent.add(contents.getContent("doclet.ClassUse_Title", cltype)); - headingContent.add(new HtmlTree(HtmlTag.BR)); + headingContent.add(HtmlTree.BR()); headingContent.add(clname); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, headingContent); 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 8218e5128be..7b271485f1f 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 @@ -165,7 +165,7 @@ protected void buildClassInfo(Content target) { buildInterfaceUsageInfo(c); buildNestedClassInfo(c); buildFunctionalInterfaceInfo(c); - c.add(new HtmlTree(HtmlTag.HR)); + c.add(HtmlTree.HR()); var div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildClassSignature(div); buildDeprecationInfo(div); @@ -461,7 +461,7 @@ private Content getTypeParameters() { var first = true; for (TypeParameterElement t : typeParams) { if (!first) { - content.add(",").add(new HtmlTree(HtmlTag.WBR)); + content.add(",").add(HtmlTree.WBR()); } var typeParamLink = getLink(linkInfo.forType(t.asType())); content.add(needsId @@ -689,11 +689,9 @@ public Void visitType(TypeElement e, Void p) { protected void addFunctionalInterfaceInfo (Content target) { if (utils.isFunctionalInterface(typeElement)) { - var dl = HtmlTree.DL(HtmlStyles.notes); - dl.add(HtmlTree.DT(contents.functionalInterface)); - var dd = new HtmlTree(HtmlTag.DD); - dd.add(contents.functionalInterfaceMessage); - dl.add(dd); + var dl = HtmlTree.DL(HtmlStyles.notes) + .add(HtmlTree.DT(contents.functionalInterface)) + .add(HtmlTree.DD(contents.functionalInterfaceMessage)); target.add(dl); } } 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 cdae0e8d911..9731cd14e88 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 @@ -414,7 +414,7 @@ void addConstantMembers(TypeElement typeElement, Collection fie */ private Content getTypeColumn(VariableElement member) { Content typeContent = new ContentBuilder(); - var code = new HtmlTree(HtmlTag.CODE) + var code = HtmlTree.CODE() .setId(htmlIds.forMember(currentTypeElement, member)); for (Modifier mod : member.getModifiers()) { code.add(Text.of(mod.toString())) 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 11975404a55..d1d04d4f7f1 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 @@ -300,7 +300,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { @Override protected void addSummaryType(Element member, Content content) { if (threeColumnSummary()) { - var code = new HtmlTree(HtmlTag.CODE); + var code = HtmlTree.CODE(); if (utils.isProtected(member)) { code.add("protected "); } else if (utils.isPrivate(member)) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java index 22e778d3986..1687f891896 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java @@ -105,11 +105,11 @@ protected void addHelpFileContents(Content content) { tableOfContents.addLink(HtmlIds.TOP_OF_PAGE, mainHeading); tableOfContents.pushNestedList(); content.add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, mainHeading)) - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(getNavigationSection()) - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(getPageKindSection()) - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(HtmlTree.SPAN(HtmlStyles.helpFootnote, getContent("doclet.help.footnote"))); tableOfContents.popNestedList(); @@ -255,7 +255,7 @@ private Content getPageKindSection() { getContent("doclet.help.class_interface.implementations"), getContent("doclet.help.class_interface.declaration"), getContent("doclet.help.class_interface.description"))) - .add(new HtmlTree(HtmlTag.BR)) + .add(HtmlTree.BR()) .add(newHelpSectionList( contents.nestedClassSummary, contents.enumConstantSummary, @@ -265,7 +265,7 @@ private Content getPageKindSection() { contents.methodSummary, contents.annotateTypeRequiredMemberSummaryLabel, contents.annotateTypeOptionalMemberSummaryLabel)) - .add(new HtmlTree(HtmlTag.BR)) + .add(HtmlTree.BR()) .add(newHelpSectionList( contents.enumConstantDetailLabel, contents.fieldDetailsLabel, 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 235a0361b92..fdf05489168 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 @@ -685,7 +685,7 @@ public HtmlTree getFooter() { return (bottom == null || bottom.isEmpty()) ? null : HtmlTree.FOOTER() - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(HtmlTree.P(HtmlStyles.legalCopy, HtmlTree.SMALL( RawHtml.of(replaceDocRootDir(bottom))))); @@ -2405,7 +2405,7 @@ static String getGenerator(Class clazz) { * @return an HtmlTree for the BODY tag */ public HtmlTree getBody(String title) { - var body = new HtmlTree(HtmlTag.BODY).setStyle(getBodyStyle()); + var body = HtmlTree.BODY(getBodyStyle()); this.winTitle = title; // Don't print windowtitle script for overview-frame, allclasses-frame @@ -2601,7 +2601,7 @@ private Content withPreviewFeatures(String key, String className, String feature }); return contents.getContent(key, HtmlTree.CODE(Text.of(className)), - new HtmlTree(HtmlTag.EM).add(featureName), + HtmlTree.EM(featureName), featureCodes); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 494d5e22d6e..bf210b91ea6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -395,14 +395,14 @@ protected Content getTypeParameterLinks(HtmlLinkInfo linkInfo) { } if (!vars.isEmpty()) { if (linkInfo.addLineBreakOpportunitiesInTypeParameters()) { - links.add(new HtmlTree(HtmlTag.WBR)); + links.add(HtmlTree.WBR()); } links.add("<"); boolean many = false; for (TypeMirror t : vars) { if (many) { links.add(","); - links.add(new HtmlTree(HtmlTag.WBR)); + links.add(HtmlTree.WBR()); if (linkInfo.addLineBreaksInTypeParameters()) { links.add(Text.NL); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java index e449ecebf40..a7afd9db85d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java @@ -92,7 +92,7 @@ public void buildPage() throws DocFileIOException { Script script = new Script("window.location.replace(") .appendStringLiteral(targetPath, '\'') .append(")"); - var metaRefresh = new HtmlTree(HtmlTag.META) + var metaRefresh = HtmlTree.of(HtmlTag.META) .put(HtmlAttr.HTTP_EQUIV, "Refresh") .put(HtmlAttr.CONTENT, "0;" + targetPath); head.addContent(script.asContent(), HtmlTree.NOSCRIPT(metaRefresh)); @@ -103,9 +103,8 @@ public void buildPage() throws DocFileIOException { bodyContent.add(HtmlTree.P(HtmlTree.A(targetPath, Text.of(targetPath)))); - var body = new HtmlTree(HtmlTag.BODY).setStyle(HtmlStyles.indexRedirectPage); - var main = HtmlTree.MAIN(bodyContent); - body.add(main); + var body = HtmlTree.BODY(HtmlStyles.indexRedirectPage) + .add(HtmlTree.MAIN(bodyContent)); HtmlDocument htmlDocument = new HtmlDocument( HtmlTree.HTML(configuration.getLocale().getLanguage(), head, body)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java index ecf11143642..87d0fa95bf3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java @@ -224,7 +224,7 @@ protected void addElementDescription(IndexItem item, Content target) { default -> throw new Error(); } target.add(dt); - var dd = new HtmlTree(HtmlTag.DD); + var dd = HtmlTree.DD(); if (element.getKind() == ElementKind.MODULE || element.getKind() == ElementKind.PACKAGE) { addSummaryComment(element, dd); } else { @@ -261,7 +261,7 @@ protected void addTagDescription(IndexItem item, Content target) { dt.add(" - "); dt.add(contents.getContent("doclet.Search_tag_in", item.getHolder())); target.add(dt); - var dd = new HtmlTree(HtmlTag.DD); + var dd = HtmlTree.DD(); if (item.getDescription().isEmpty()) { dd.add(Entity.NO_BREAK_SPACE); } else { @@ -348,7 +348,7 @@ protected void addLinksForIndexes(List allFirstCharacters, Content co content.add(Entity.NO_BREAK_SPACE); } - content.add(new HtmlTree(HtmlTag.BR)); + content.add(HtmlTree.BR()); var pageLinks = Stream.of(IndexItem.Category.values()) .flatMap(c -> mainIndex.getItems(c).stream()) .filter(i -> !(i.isElementItem() || i.isTagItem())) 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 bd0ab2958d4..b688420681f 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 @@ -194,7 +194,7 @@ protected void buildModuleDoc() throws DocletException { */ protected void buildContent() { Content moduleContent = getContentHeader(); - moduleContent.add(new HtmlTree(HtmlTag.HR)); + moduleContent.add(HtmlTree.HR()); Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); addModuleSignature(div); buildModuleDescription(div); @@ -825,7 +825,7 @@ public void addProvidesList(Table table) { } // Only display the implementation details in the "all" mode. if (moduleMode == ModuleMode.ALL && !implSet.isEmpty()) { - desc.add(new HtmlTree(HtmlTag.BR)); + desc.add(HtmlTree.BR()); desc.add("("); var implSpan = HtmlTree.SPAN(HtmlStyles.implementationLabel, contents.implementation); desc.add(implSpan); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 293a6453925..9d12d3bb23d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -516,14 +516,14 @@ public Content getContent() { } var navigationBar = HtmlTree.NAV(); - var navContent = new HtmlTree(HtmlTag.DIV); + var navContent = HtmlTree.DIV(HtmlStyles.navContent); Content skipNavLinks = contents.getContent("doclet.Skip_navigation_links"); String toggleNavLinks = configuration.getDocResources().getText("doclet.Toggle_navigation_links"); navigationBar.add(MarkerComments.START_OF_TOP_NAVBAR); // The mobile menu button uses three empty spans to produce its animated icon HtmlTree iconSpan = HtmlTree.SPAN(HtmlStyles.navBarToggleIcon).add(Entity.NO_BREAK_SPACE); - navContent.setStyle(HtmlStyles.navContent).add(HtmlTree.DIV(HtmlStyles.navMenuButton, - new HtmlTree(HtmlTag.BUTTON).setId(HtmlIds.NAVBAR_TOGGLE_BUTTON) + navContent.add(HtmlTree.DIV(HtmlStyles.navMenuButton, + HtmlTree.BUTTON(HtmlIds.NAVBAR_TOGGLE_BUTTON) .put(HtmlAttr.ARIA_CONTROLS, HtmlIds.NAVBAR_TOP.name()) .put(HtmlAttr.ARIA_EXPANDED, String.valueOf(false)) .put(HtmlAttr.ARIA_LABEL, toggleNavLinks) @@ -535,9 +535,7 @@ public Content getContent() { skipNavLinks.toString()))); Content aboutContent = userHeader; - var navList = new HtmlTree(HtmlTag.UL) - .setId(HtmlIds.NAVBAR_TOP_FIRSTROW) - .setStyle(HtmlStyles.navList) + var navList = HtmlTree.UL(HtmlIds.NAVBAR_TOP_FIRSTROW, HtmlStyles.navList) .put(HtmlAttr.TITLE, rowListTitle); addMainNavLinks(navList); navContent.add(navList); 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 b28b44d4cd3..078f5246de7 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 @@ -204,7 +204,7 @@ private HtmlTree getBody() { HtmlTree body = getBody(getWindowTitle(title)); ContentBuilder headingContent = new ContentBuilder(); headingContent.add(contents.getContent("doclet.ClassUse_Title", packageText)); - headingContent.add(new HtmlTree(HtmlTag.BR)); + headingContent.add(HtmlTree.BR()); headingContent.add(name); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, headingContent); 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 ee022144fea..d5683ec6e3c 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 @@ -128,7 +128,7 @@ protected void buildPackageDoc() throws DocletException { */ protected void buildContent() { Content packageContent = getContentHeader(); - packageContent.add(new HtmlTree(HtmlTag.HR)); + packageContent.add(HtmlTree.HR()); Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); addPackageSignature(div); buildPackageDescription(div); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java index 0bd173df3d5..c30dae6bc65 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java @@ -97,24 +97,21 @@ protected void addSearchFileContents(Content contentTree) { .add(HtmlTree.P(contents.getContent("doclet.search.browser_info"))) .add(HtmlTree.SPAN(Text.of("link")) .setId(HtmlId.of("page-search-link"))) - .add(new HtmlTree(HtmlTag.BUTTON) - .add(new HtmlTree(HtmlTag.IMG) + .add(HtmlTree.BUTTON(HtmlId.of("page-search-copy")) + .add(HtmlTree.of(HtmlTag.IMG) .put(HtmlAttr.SRC, pathToRoot.resolve(DocPaths.RESOURCE_FILES) .resolve(DocPaths.CLIPBOARD_SVG).getPath()) .put(HtmlAttr.ALT, copyUrlText)) .add(HtmlTree.SPAN(Text.of(copyText)) .put(HtmlAttr.DATA_COPIED, copiedText)) .addStyle(HtmlStyles.copy) - .put(HtmlAttr.ARIA_LABEL, copyUrlText) - .setId(HtmlId.of("page-search-copy"))) + .put(HtmlAttr.ARIA_LABEL, copyUrlText)) .add(HtmlTree.P(HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, HtmlId.of("search-redirect"))) .add(HtmlTree.LABEL("search-redirect", contents.getContent("doclet.search.redirect"))))) - .add(new HtmlTree(HtmlTag.P) - .setId(HtmlId.of("page-search-notify")) - .add(contents.getContent("doclet.search.loading"))) - .add(HtmlTree.DIV(new HtmlTree(HtmlTag.DIV) - .setId(HtmlId.of("result-container")) + .add(HtmlTree.P(contents.getContent("doclet.search.loading")) + .setId(HtmlId.of("page-search-notify"))) + .add(HtmlTree.DIV(HtmlTree.DIV(HtmlId.of("result-container")) .addUnchecked(Text.EMPTY)) .setId(HtmlId.of("result-section")) .put(HtmlAttr.STYLE, "display: none;") diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java index c3d1cc582f3..ef9810f7374 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java @@ -58,7 +58,7 @@ protected Content getSerializableFieldsHeader() { } protected Content getFieldsContentHeader() { - return new HtmlTree(HtmlTag.LI).setStyle(HtmlStyles.blockList); + return HtmlTree.LI(HtmlStyles.blockList); } protected Content getSerializableFields(String heading, Content source) { @@ -76,12 +76,12 @@ protected void addMemberHeader(TypeMirror fieldType, String fieldName, Content c Content nameContent = Text.of(fieldName); var heading = HtmlTree.HEADING(Headings.SerializedForm.MEMBER_HEADING, nameContent); content.add(heading); - var pre = new HtmlTree(HtmlTag.PRE); Content fieldContent = writer.getLink(new HtmlLinkInfo( configuration, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, fieldType)); - pre.add(fieldContent); - pre.add(" "); - pre.add(fieldName); + var pre = HtmlTree.PRE() + .add(fieldContent) + .add(" ") + .add(fieldName); content.add(pre); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java index d9b888f2ee1..4ce7d662abb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java @@ -51,7 +51,7 @@ protected Content getSerializableMethodsHeader() { } protected Content getMethodsContentHeader() { - return new HtmlTree(HtmlTag.LI); + return HtmlTree.LI(); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java index 9059efcf814..f1e26879ef4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java @@ -569,7 +569,7 @@ private void appendParametersAndExceptions(Content target, int lastLineSeparator // empty parameters are added without packing target.add(parameters); } else { - target.add(new HtmlTree(HtmlTag.WBR)) + target.add(HtmlTree.WBR()) .add(HtmlTree.SPAN(HtmlStyles.parameters, parameters)); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java index 070b3842122..aa20fc8c9ae 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java @@ -201,7 +201,7 @@ public void convertClass(TypeElement te, DocPath outputdir) .resolve(configuration.docPaths.forPackage(te)) .invert(); Content body = getHeader(); - var pre = new HtmlTree(HtmlTag.PRE); + var pre = HtmlTree.PRE(); try (var reader = new LineNumberReader(r)) { while ((line = reader.readLine()) != null) { addLineNo(pre, lineno); @@ -246,7 +246,7 @@ private void writeToFile(Content body, DocPath path, TypeElement te) throws DocF * @return the header content for the HTML file */ private static Content getHeader() { - return new HtmlTree(HtmlTag.BODY).setStyle(HtmlStyles.sourcePage); + return HtmlTree.BODY(HtmlStyles.sourcePage); } /** 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 5d09682d492..0e09920b7b1 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 @@ -361,7 +361,7 @@ public boolean write(Writer out, String newline, boolean atNewline) throws IOExc private Content toContent() { Content main; if (id != null) { - main = new HtmlTree(HtmlTag.DIV).setId(id); + main = HtmlTree.DIV(id); } else { main = new ContentBuilder(); } @@ -403,8 +403,7 @@ private Content toContent() { if (id == null) { throw new IllegalStateException("no id set for table"); } - var tabpanel = new HtmlTree(HtmlTag.DIV) - .setId(HtmlIds.forTabPanel(id)) + var tabpanel = HtmlTree.DIV(HtmlIds.forTabPanel(id)) .put(HtmlAttr.ROLE, "tabpanel") .put(HtmlAttr.ARIA_LABELLEDBY, defaultTabId.name()); table.add(getTableBody()); @@ -416,8 +415,7 @@ private Content toContent() { } private HtmlTree createTab(HtmlId tabId, HtmlStyle style, boolean defaultTab, Content tabLabel) { - var tab = new HtmlTree(HtmlTag.BUTTON) - .setId(tabId) + var tab = HtmlTree.BUTTON(tabId) .put(HtmlAttr.ROLE, "tab") .put(HtmlAttr.ARIA_SELECTED, defaultTab ? "true" : "false") .put(HtmlAttr.ARIA_CONTROLS, HtmlIds.forTabPanel(id).name()) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java index a9036d7dcd8..cfb8f7260d0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java @@ -101,10 +101,10 @@ protected Content toContent(boolean hasFilterInput) { .put(HtmlAttr.VALUE, writer.resources.getText("doclet.filter_reset"))); } content.add(header); - content.add(new HtmlTree(HtmlTag.BUTTON).addStyle(HtmlStyles.hideSidebar) + content.add(HtmlTree.BUTTON(HtmlStyles.hideSidebar) .add(HtmlTree.SPAN(writer.contents.hideSidebar).add(Entity.NO_BREAK_SPACE)) .add(Entity.LEFT_POINTING_ANGLE)); - content.add(new HtmlTree(HtmlTag.BUTTON).addStyle(HtmlStyles.showSidebar) + content.add(HtmlTree.BUTTON(HtmlStyles.showSidebar) .add(Entity.RIGHT_POINTING_ANGLE) .add(HtmlTree.SPAN(Entity.NO_BREAK_SPACE).add(writer.contents.showSidebar))); return content.add(listBuilder); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 3d5b1a494ba..9b6b1c831b1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -272,9 +272,9 @@ public boolean write(Writer out, String newline, boolean atNewline) throws IOExc * @return the HTML */ private Content toContent() { - var head = new HtmlTree(HtmlTag.HEAD); - head.add(getGeneratedBy(showTimestamp, generatedDate)); - head.add(HtmlTree.TITLE(title)); + var head = HtmlTree.of(HtmlTag.HEAD) + .add(getGeneratedBy(showTimestamp, generatedDate)) + .add(HtmlTree.TITLE(title)); head.add(HtmlTree.META("viewport", "width=device-width, initial-scale=1")); @@ -300,9 +300,9 @@ private Content toContent() { } if (canonicalLink != null) { - var link = new HtmlTree(HtmlTag.LINK); - link.put(HtmlAttr.REL, "canonical"); - link.put(HtmlAttr.HREF, canonicalLink.getPath()); + var link = HtmlTree.of(HtmlTag.LINK) + .put(HtmlAttr.REL, "canonical") + .put(HtmlAttr.HREF, canonicalLink.getPath()); head.add(link); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index af2378c0351..93f83c5ba90 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -122,13 +122,13 @@ public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter tagl private Content snippetTagOutput(Element element, SnippetTree tag, StyledText content, String id, String lang) { var pathToRoot = tagletWriter.htmlWriter.pathToRoot; - var pre = new HtmlTree(HtmlTag.PRE).setStyle(HtmlStyles.snippet); + var pre = HtmlTree.PRE(HtmlStyles.snippet); if (id != null && !id.isBlank()) { pre.put(HtmlAttr.ID, id); } else { pre.put(HtmlAttr.ID, config.htmlIds.forSnippet(element, ids).name()); } - var code = new HtmlTree(HtmlTag.CODE) + var code = HtmlTree.CODE() .addUnchecked(Text.EMPTY); // Make sure the element is always rendered if (lang != null && !lang.isBlank()) { code.addStyle("language-" + lang); @@ -197,10 +197,10 @@ private Content snippetTagOutput(Element element, SnippetTree tag, StyledText co String copiedText = resources.getText("doclet.Copied_to_clipboard"); String copySnippetText = resources.getText("doclet.Copy_snippet_to_clipboard"); var snippetContainer = HtmlTree.DIV(HtmlStyles.snippetContainer, - new HtmlTree(HtmlTag.BUTTON) + HtmlTree.of(HtmlTag.BUTTON) .add(HtmlTree.SPAN(Text.of(copyText)) .put(HtmlAttr.DATA_COPIED, copiedText)) - .add(new HtmlTree(HtmlTag.IMG) + .add(HtmlTree.of(HtmlTag.IMG) .put(HtmlAttr.SRC, pathToRoot.resolve(DocPaths.RESOURCE_FILES) .resolve(DocPaths.CLIPBOARD_SVG).getPath()) .put(HtmlAttr.ALT, copySnippetText)) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java index f6053751174..f1ca45cc040 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java @@ -83,7 +83,17 @@ public class HtmlTree extends Content { * * @param tag the name */ - public HtmlTree(HtmlTag tag) { + public static HtmlTree of(HtmlTag tag) { + return new HtmlTree(tag); + } + + /** + * Creates an {@code HTMLTree} object representing an HTML element + * with the given name. + * + * @param tag the name + */ + HtmlTree(HtmlTag tag) { this.tag = Objects.requireNonNull(tag); } @@ -365,6 +375,46 @@ public static HtmlTree A(URI ref, Content body) { .add(body); } + /** + * Creates an HTML {@code BODY} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree BODY(HtmlStyle style) { + return new HtmlTree(HtmlTag.BODY) + .setStyle(style); + } + + private static final HtmlTree BR_INSTANCE = unmodifiableTree(HtmlTag.BR); + + /** + * {@return an HTML {@code BR} element} + */ + public static HtmlTree BR() { + return BR_INSTANCE; + } + + /** + * Creates an HTML {@code BUTTON} element with the given id. + * + * @param id the id + * @return the element + */ + public static HtmlTree BUTTON(HtmlId id) { + return new HtmlTree(HtmlTag.BUTTON).setId(id); + } + + /** + * Creates an HTML {@code BUTTON} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree BUTTON(HtmlStyle style) { + return new HtmlTree(HtmlTag.BUTTON).setStyle(style); + } + /** * Creates an HTML {@code CAPTION} element with the given content. * @@ -376,6 +426,15 @@ public static HtmlTree CAPTION(Content body) { .add(body); } + /** + * Creates an empty HTML {@code CODE} element. + * + * @return the element + */ + public static HtmlTree CODE() { + return new HtmlTree(HtmlTag.CODE); + } + /** * Creates an HTML {@code CODE} element with the given content. * @@ -387,6 +446,15 @@ public static HtmlTree CODE(Content body) { .add(body); } + /** + * Creates an empty HTML {@code DD} element. + * + * @return the element + */ + public static HtmlTree DD() { + return new HtmlTree(HtmlTag.DD); + } + /** * Creates an HTML {@code DD} element with the given content. * @@ -418,27 +486,14 @@ public static HtmlTree DETAILS(HtmlStyle style) { } /** - * Creates an HTML {@code DL} element with the given style. + * Creates an HTML {@code DIV} element with the given id. * - * @param style the style + * @param id the id * @return the element */ - public static HtmlTree DL(HtmlStyle style) { - return new HtmlTree(HtmlTag.DL) - .setStyle(style); - } - - /** - * Creates an HTML {@code DL} element with the given style and content. - * - * @param style the style - * @param body the content - * @return the element - */ - public static HtmlTree DL(HtmlStyle style, Content body) { - return new HtmlTree(HtmlTag.DL) - .setStyle(style) - .add(body); + public static HtmlTree DIV(HtmlId id) { + return new HtmlTree(HtmlTag.DIV) + .setId(id); } /** @@ -476,6 +531,30 @@ public static HtmlTree DIV(Content body) { .add(body); } + /** + * Creates an HTML {@code DL} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree DL(HtmlStyle style) { + return new HtmlTree(HtmlTag.DL) + .setStyle(style); + } + + /** + * Creates an HTML {@code DL} element with the given style and content. + * + * @param style the style + * @param body the content + * @return the element + */ + public static HtmlTree DL(HtmlStyle style, Content body) { + return new HtmlTree(HtmlTag.DL) + .setStyle(style) + .add(body); + } + /** * Creates an HTML {@code DT} element with the given content. * @@ -487,6 +566,17 @@ public static HtmlTree DT(Content body) { .add(body); } + /** + * Creates an HTML {@code EM} element with the given content. + * + * @param body content for the element + * @return the element + */ + public static HtmlTree EM(String body) { + return new HtmlTree(HtmlTag.EM) + .add(body); + } + /** * Creates an HTML {@code FOOTER} element. * The role is set to {@code contentinfo}. @@ -573,6 +663,15 @@ private static HtmlTag checkHeading(HtmlTag headingTag) { }; } + private static final HtmlTree HR_INSTANCE = unmodifiableTree(HtmlTag.HR); + + /** + * {@return an HTML {@code HR} element} + */ + public static HtmlTree HR() { + return HR_INSTANCE; + } + /** * Creates an HTML {@code HTML} element with the given {@code lang} attribute, * and {@code HEAD} and {@code BODY} contents. @@ -630,6 +729,27 @@ public static HtmlTree LABEL(String forLabel, Content body) { .add(body); } + /** + * Creates an empty HTML {@code LI} element. + * + * @return the element + */ + public static HtmlTree LI() { + return new HtmlTree(HtmlTag.LI); + } + + + /** + * Creates an HTML {@code LI} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree LI(HtmlStyle style) { + return new HtmlTree(HtmlTag.LI) + .setStyle(style); + } + /** * Creates an HTML {@code LI} element with the given content. * @@ -776,6 +896,25 @@ public static HtmlTree P(HtmlStyle style, Content body) { .setStyle(style); } + /** + * Creates an empty HTML {@code PRE} element. + * + * @return the element + */ + public static HtmlTree PRE() { + return new HtmlTree(HtmlTag.PRE); + } + + /** + * Creates an HTML {@code PRE} element with the given style + * + * @param style the style + * @return the element + */ + public static HtmlTree PRE(HtmlStyle style) { + return new HtmlTree(HtmlTag.PRE).setStyle(style); + } + /** * Creates an HTML {@code PRE} element with some content. * @@ -971,6 +1110,15 @@ public static HtmlTree TITLE(String body) { .add(body); } + /** + * Creates an empty HTML {@code UL} element. + * + * @return the element + */ + public static HtmlTree UL() { + return new HtmlTree(HtmlTag.UL); + } + /** * Creates an HTML {@code UL} element with the given style. * @@ -982,6 +1130,19 @@ public static HtmlTree UL(HtmlStyle style) { .setStyle(style); } + /** + * Creates an HTML {@code UL} element with the given id and style. + * + * @param id the id + * @param style the style + * @return the element + */ + public static HtmlTree UL(HtmlId id, HtmlStyle style) { + return new HtmlTree(HtmlTag.UL) + .setId(id) + .setStyle(style); + } + /** * Creates an HTML {@code UL} element with the given style and some content. * @@ -1015,6 +1176,15 @@ public static HtmlTree UL(HtmlStyle style, Collection items, Function * A type declaration is {@linkplain Kind#isPersistent() persistent}. * - * @jls 7.6 Top Level Type Declarations + * @jls 7.6 Top Level Class and Interface Declarations */ TYPE_DECL(true), @@ -241,14 +241,14 @@ public enum SubKind { /** * An enum declaration. * A {@code SubKind} of {@link Kind#TYPE_DECL}. - * @jls 8.9 Enum Types + * @jls 8.9 Enum Classes */ ENUM_SUBKIND(Kind.TYPE_DECL), /** * A record declaration. * A {@code SubKind} of {@link Kind#TYPE_DECL}. - * @jls 8.10 Record Types + * @jls 8.10 Record Classes * * @since 17 */ @@ -257,7 +257,7 @@ public enum SubKind { /** * An annotation interface declaration. A {@code SubKind} of * {@link Kind#TYPE_DECL}. - * @jls 9.6 Annotation Types + * @jls 9.6 Annotation Interfaces */ ANNOTATION_TYPE_SUBKIND(Kind.TYPE_DECL), diff --git a/src/jdk.management/share/classes/com/sun/management/OperatingSystemMXBean.java b/src/jdk.management/share/classes/com/sun/management/OperatingSystemMXBean.java index bd9009cff15..d20d1ead35f 100644 --- a/src/jdk.management/share/classes/com/sun/management/OperatingSystemMXBean.java +++ b/src/jdk.management/share/classes/com/sun/management/OperatingSystemMXBean.java @@ -130,18 +130,27 @@ public interface OperatingSystemMXBean extends public long getTotalMemorySize(); /** - * Returns the "recent cpu usage" for the whole system. This value is a + * Returns the "recent CPU usage" for the whole system. This value is a * double in the [0.0,1.0] interval. A value of 0.0 means that all CPUs * were idle during the recent period of time observed, while a value * of 1.0 means that all CPUs were actively running 100% of the time - * during the recent period being observed. All values between 0.0 and - * 1.0 are possible depending of the activities going on in the system. - * If the system recent cpu usage is not available, the method returns a + * during the recent period being observed. + * + * The recent period of observation is implementation-specific, and + * typically relates to the duration since the last call made to this + * method, or {@link #getCpuLoad()}. For the very first invocation, the + * recent period of observation is undefined. + * + * All values between 0.0 and 1.0 are possible dependent on the activities + * going on. If the recent CPU usage is not available, the method returns a * negative value. * * @deprecated Use {@link #getCpuLoad()} instead of * this historically named method. * + * @apiNote Callers should be aware of the possibility of other callers + * affecting the observation period and the result. + * * @implSpec This implementation must return the same value * as {@link #getCpuLoad()}. * @@ -153,15 +162,24 @@ public interface OperatingSystemMXBean extends public default double getSystemCpuLoad() { return getCpuLoad(); } /** - * Returns the "recent cpu usage" for the operating environment. This value + * Returns the "recent CPU usage" for the operating environment. This value * is a double in the [0.0,1.0] interval. A value of 0.0 means that all CPUs * were idle during the recent period of time observed, while a value * of 1.0 means that all CPUs were actively running 100% of the time - * during the recent period being observed. All values between 0.0 and - * 1.0 are possible depending of the activities going on. - * If the recent cpu usage is not available, the method returns a + * during the recent period being observed. + * + * The recent period of observation is implementation-specific, and + * typically relates to the duration since the last call made to this + * method, or {@link #getSystemCpuLoad()}. For the very first invocation, + * the recent period of observation is undefined. + * + * All values between 0.0 and 1.0 are possible dependent on the activities + * going on. If the recent CPU usage is not available, the method returns a * negative value. * + * @apiNote Callers should be aware of the possibility of other callers + * affecting the observation period and the result. + * * @return the "recent cpu usage" for the whole operating environment; * a negative value if not available. * @since 14 @@ -169,16 +187,26 @@ public interface OperatingSystemMXBean extends public double getCpuLoad(); /** - * Returns the "recent cpu usage" for the Java Virtual Machine process. + * Returns the "recent CPU usage" for the Java Virtual Machine process. * This value is a double in the [0.0,1.0] interval. A value of 0.0 means * that none of the CPUs were running threads from the JVM process during * the recent period of time observed, while a value of 1.0 means that all * CPUs were actively running threads from the JVM 100% of the time * during the recent period being observed. Threads from the JVM include - * the application threads as well as the JVM internal threads. All values - * between 0.0 and 1.0 are possible depending of the activities going on - * in the JVM process and the whole system. If the Java Virtual Machine - * recent CPU usage is not available, the method returns a negative value. + * the application threads as well as the JVM internal threads. + * + * The recent period of observation is implementation-specific, and + * typically relates to the duration since the last call made to this + * method. For the very first invocation, the recent period of observation + * is undefined. + * + * All values between 0.0 and 1.0 are possible dependent on the activities + * going on in the JVM process and the whole system. If the Java Virtual + * Machine recent CPU usage is not available, the method returns a negative + * value. + * + * @apiNote Callers should be aware of the possibility of other callers + * affecting the observation period and the result. * * @return the "recent cpu usage" for the Java Virtual Machine process; * a negative value if not available. diff --git a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java index cdc5998426d..721f03e7de1 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -41,6 +41,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import javax.management.DynamicMBean; +import jdk.management.VirtualThreadSchedulerMXBean; import sun.management.ManagementFactoryHelper; import sun.management.spi.PlatformMBeanProvider; @@ -163,6 +164,41 @@ public synchronized Map nameToMBeanMa } }); + /** + * VirtualThreadSchedulerMXBean. + */ + initMBeanList.add(new PlatformComponent() { + private final Set> mbeanInterfaces = + Set.of(VirtualThreadSchedulerMXBean.class); + private final Set mbeanInterfaceNames = + Set.of(VirtualThreadSchedulerMXBean.class.getName()); + private VirtualThreadSchedulerMXBean impl; + + @Override + public Set> mbeanInterfaces() { + return mbeanInterfaces; + } + + @Override + public Set mbeanInterfaceNames() { + return mbeanInterfaceNames; + } + + @Override + public String getObjectNamePattern() { + return "jdk.management:type=VirtualThreadScheduler"; + } + + @Override + public Map nameToMBeanMap() { + VirtualThreadSchedulerMXBean impl = this.impl; + if (impl == null) { + this.impl = impl = VirtualThreadSchedulerImpls.create(); + } + return Map.of("jdk.management:type=VirtualThreadScheduler", impl); + } + }); + /** * OperatingSystemMXBean */ diff --git a/src/jdk.management/share/classes/com/sun/management/internal/VirtualThreadSchedulerImpls.java b/src/jdk.management/share/classes/com/sun/management/internal/VirtualThreadSchedulerImpls.java new file mode 100644 index 00000000000..8787237f903 --- /dev/null +++ b/src/jdk.management/share/classes/com/sun/management/internal/VirtualThreadSchedulerImpls.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.management.internal; + +import java.util.concurrent.Executor; +import java.util.concurrent.ForkJoinPool; +import javax.management.ObjectName; +import jdk.management.VirtualThreadSchedulerMXBean; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.vm.ContinuationSupport; +import sun.management.Util; + +/** + * Provides the implementation of the management interface for the JDK's default virtual + * thread scheduler. + */ +public class VirtualThreadSchedulerImpls { + private VirtualThreadSchedulerImpls() { + } + + public static VirtualThreadSchedulerMXBean create() { + if (ContinuationSupport.isSupported()) { + return new VirtualThreadSchedulerImpl(); + } else { + return new BoundVirtualThreadSchedulerImpl(); + } + } + + /** + * Base implementation of VirtualThreadSchedulerMXBean. + */ + private abstract static class BaseVirtualThreadSchedulerImpl + implements VirtualThreadSchedulerMXBean { + + abstract void implSetParallelism(int size); + + @Override + public final void setParallelism(int size) { + Util.checkControlAccess(); + implSetParallelism(size); + } + + @Override + public final ObjectName getObjectName() { + return Util.newObjectName("jdk.management:type=VirtualThreadScheduler"); + } + + @Override + public String toString() { + var sb = new StringBuilder("[parallelism="); + sb.append(getParallelism()); + append(sb, "size", getPoolSize()); + append(sb, "mounted", getMountedVirtualThreadCount()); + append(sb, "queued", getQueuedVirtualThreadCount()); + sb.append(']'); + return sb.toString(); + } + + private void append(StringBuilder sb, String name, long value) { + sb.append(", ").append(name).append('='); + if (value >= 0) { + sb.append(value); + } else { + sb.append(""); + } + } + } + + /** + * Implementation of VirtualThreadSchedulerMXBean when virtual threads are + * implemented with continuations + scheduler. + */ + private static final class VirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl { + /** + * Holder class for scheduler. + */ + private static class Scheduler { + private static final Executor scheduler = + SharedSecrets.getJavaLangAccess().virtualThreadDefaultScheduler(); + static Executor instance() { + return scheduler; + } + } + + @Override + public int getParallelism() { + if (Scheduler.instance() instanceof ForkJoinPool pool) { + return pool.getParallelism(); + } + throw new InternalError(); // should not get here + } + + @Override + void implSetParallelism(int size) { + if (Scheduler.instance() instanceof ForkJoinPool pool) { + pool.setParallelism(size); + if (pool.getPoolSize() < size) { + // FJ worker thread creation is on-demand + Thread.startVirtualThread(() -> { }); + } + + return; + } + throw new UnsupportedOperationException(); // should not get here + } + + @Override + public int getPoolSize() { + if (Scheduler.instance() instanceof ForkJoinPool pool) { + return pool.getPoolSize(); + } + return -1; // should not get here + } + + @Override + public int getMountedVirtualThreadCount() { + if (Scheduler.instance() instanceof ForkJoinPool pool) { + return pool.getActiveThreadCount(); + } + return -1; // should not get here + } + + @Override + public long getQueuedVirtualThreadCount() { + if (Scheduler.instance() instanceof ForkJoinPool pool) { + return pool.getQueuedTaskCount() + pool.getQueuedSubmissionCount(); + } + return -1L; // should not get here + } + } + + /** + * Implementation of VirtualThreadSchedulerMXBean when virtual threads are backed + * by platform threads. + */ + private static final class BoundVirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl { + @Override + public int getParallelism() { + return Integer.MAX_VALUE; + } + + @Override + void implSetParallelism(int size) { + throw new UnsupportedOperationException(); + } + + @Override + public int getPoolSize() { + return -1; + } + + @Override + public int getMountedVirtualThreadCount() { + return -1; + } + + @Override + public long getQueuedVirtualThreadCount() { + return -1L; + } + } +} \ No newline at end of file diff --git a/src/jdk.management/share/classes/com/sun/management/package-info.java b/src/jdk.management/share/classes/com/sun/management/package-info.java index 0af2f33e8c7..453b4c1517f 100644 --- a/src/jdk.management/share/classes/com/sun/management/package-info.java +++ b/src/jdk.management/share/classes/com/sun/management/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, 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,9 +24,8 @@ */ /** - * This package contains the JDK's extension to - * the standard implementation of the - * {@link java.lang.management} API and also defines the management + * This package contains JDK extensions to the standard implementation of + * the {@link java.lang.management} API and also defines the management * interface for some other components of the platform. * *

        diff --git a/src/jdk.management/share/classes/jdk/management/VirtualThreadSchedulerMXBean.java b/src/jdk.management/share/classes/jdk/management/VirtualThreadSchedulerMXBean.java new file mode 100644 index 00000000000..556c5184ffe --- /dev/null +++ b/src/jdk.management/share/classes/jdk/management/VirtualThreadSchedulerMXBean.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.management; + +import java.lang.management.ManagementFactory; +import java.lang.management.PlatformManagedObject; +import java.util.concurrent.ForkJoinPool; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * Management interface for the JDK's {@linkplain Thread##virtual-threads virtual thread} + * scheduler. + * + *

        {@code VirtualThreadSchedulerMXBean} supports monitoring of the virtual thread + * scheduler's target parallelism, the {@linkplain Thread##platform-threads platform threads} + * used by the scheduler, and the number of virtual threads queued to the scheduler. It + * also supports dynamically changing the scheduler's target parallelism. + * + *

        The management interface is registered with the platform {@link MBeanServer + * MBeanServer}. The {@link ObjectName ObjectName} that uniquely identifies the management + * interface within the {@code MBeanServer} is: "jdk.management:type=VirtualThreadScheduler". + * + *

        Direct access to the MXBean interface can be obtained with + * {@link ManagementFactory#getPlatformMXBean(Class)}. + * + * @since 24 + */ +public interface VirtualThreadSchedulerMXBean extends PlatformManagedObject { + + /** + * {@return the scheduler's target parallelism} + * + * @see ForkJoinPool#getParallelism() + */ + int getParallelism(); + + /** + * Sets the scheduler's target parallelism. + * + *

        Increasing the target parallelism allows the scheduler to use more platform + * threads to carry virtual threads if required. Decreasing the target parallelism + * reduces the number of threads that the scheduler may use to carry virtual threads. + * + * @apiNote If virtual threads are mounting and unmounting frequently then downward + * adjustment of the target parallelism will likely come into effect quickly. + * + * @implNote The JDK's virtual thread scheduler is a {@link ForkJoinPool}. Target + * parallelism defaults to the number of {@linkplain Runtime#availableProcessors() + * available processors}. The minimum target parallelism is 1, the maximum target + * parallelism is 32767. + * + * @param size the target parallelism level + * @throws IllegalArgumentException if size is less than the minimum, or + * greater than the maximum, supported by the scheduler + * @throws UnsupportedOperationException if changing the target + * parallelism is not suppored by the scheduler + * + * @see ForkJoinPool#setParallelism(int) + */ + void setParallelism(int size); + + /** + * {@return the current number of platform threads that the scheduler has started + * but have not terminated; {@code -1} if not known} + * + *

        The count includes the platform threads that are currently carrying + * virtual threads and the platform threads that are not currently carrying virtual + * threads. The thread count may be greater than the scheduler's target parallelism. + * + * @implNote The JDK's virtual thread scheduler is a {@link ForkJoinPool}. The pool + * size is the {@linkplain ForkJoinPool#getPoolSize() number of worker threads}. + */ + int getPoolSize(); + + /** + * {@return an estimate of the number of virtual threads that are currently + * mounted by the scheduler; {@code -1} if not known} + * + *

        The number of mounted virtual threads is equal to the number of platform + * threads carrying virtual threads. + * + * @implNote This method may overestimate the number of virtual threads that are mounted. + */ + int getMountedVirtualThreadCount(); + + /** + * {@return an estimate of the number of virtual threads that are queued to + * the scheduler to start or continue execution; {@code -1} if not known} + * + * @implNote This method may overestimate the number of virtual threads that are + * queued to execute. + */ + long getQueuedVirtualThreadCount(); +} \ No newline at end of file diff --git a/src/java.base/share/classes/sun/security/provider/SHAKE128.java b/src/jdk.management/share/classes/jdk/management/package-info.java similarity index 67% rename from src/java.base/share/classes/sun/security/provider/SHAKE128.java rename to src/jdk.management/share/classes/jdk/management/package-info.java index 0d62497b3b4..f34a8e76373 100644 --- a/src/java.base/share/classes/sun/security/provider/SHAKE128.java +++ b/src/jdk.management/share/classes/jdk/management/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,28 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package sun.security.provider; -/* - * The SHAKE128 extendable output function. +/** + * This package contains JDK extensions to the standard implementation of the + * {@link java.lang.management} API. + * + * @since 24 */ -public final class SHAKE128 extends SHA3 { - public SHAKE128(int d) { - super("SHAKE128", d, (byte) 0x1F, 32); - } - - public void update(byte in) { - engineUpdate(in); - } - public void update(byte[] in, int off, int len) { - engineUpdate(in, off, len); - } - - public byte[] digest() { - return engineDigest(); - } - public void reset() { - engineReset(); - } -} +package jdk.management; \ No newline at end of file diff --git a/src/jdk.management/share/classes/module-info.java b/src/jdk.management/share/classes/module-info.java index 092480de9e5..4fc747f55d4 100644 --- a/src/jdk.management/share/classes/module-info.java +++ b/src/jdk.management/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,18 @@ * questions. */ +import java.lang.management.ManagementFactory; + /** * Defines JDK-specific management interfaces for the JVM. * + *

        This module contains the JDK's extensions to the standard implementation + * of the {@link java.lang.management} API and also defines the management + * interfaces for some other components of the platform. + * + *

        All platform MBeans are registered in the platform MBeanServer + * which can be obtained with {@link ManagementFactory#getPlatformMBeanServer}. + * * @moduleGraph * @since 9 */ @@ -33,6 +42,7 @@ requires transitive java.management; exports com.sun.management; + exports jdk.management; provides sun.management.spi.PlatformMBeanProvider with com.sun.management.internal.PlatformMBeanProviderImpl; diff --git a/src/utils/hsdis/binutils/hsdis-binutils.c b/src/utils/hsdis/binutils/hsdis-binutils.c index fda6a53a6d3..3e3362cac94 100644 --- a/src/utils/hsdis/binutils/hsdis-binutils.c +++ b/src/utils/hsdis/binutils/hsdis-binutils.c @@ -61,14 +61,10 @@ #include #include +#include #include "hsdis.h" -#ifndef bool -#define bool int -#define true 1 -#define false 0 -#endif /*bool*/ /* short names for stuff in hsdis.h */ typedef decode_instructions_event_callback_ftype event_callback_t; diff --git a/test/hotspot/gtest/gc/z/test_zForwarding.cpp b/test/hotspot/gtest/gc/z/test_zForwarding.cpp index 622c6d9d8f4..ff2b3ee01e1 100644 --- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp +++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp @@ -225,7 +225,7 @@ class ZForwardingTest : public Test { const ZPhysicalMemory pmem(ZPhysicalMemorySegment(zoffset(0), ZPageSizeSmall, true)); ZPage page(ZPageType::small, vmem, pmem); - page.reset(ZPageAge::eden, ZPageResetType::Allocation); + page.reset(ZPageAge::eden); const size_t object_size = 16; const zaddress object = page.alloc_object(object_size); diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index 0f054a3bd72..f2af6372aa4 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -75,7 +75,7 @@ class TestController : public CgroupController { char* _path; public: TestController(char* p): _path(p) {} - char* subsystem_path() override { + const char* subsystem_path() override { return _path; }; bool is_read_only() override { @@ -470,4 +470,88 @@ TEST(cgroupTest, set_cgroupv2_subsystem_path) { } } +TEST(cgroupTest, cgroupv2_is_hierarchy_walk_needed) { + bool controller_read_only = false; // value irrelevant; + CgroupV2Controller* test = new CgroupV2Controller((char*)"/sys/fs/cgroup", + (char*)"/" /* cgroup_path */, + controller_read_only); + EXPECT_FALSE(test->needs_hierarchy_adjustment()); + test = new CgroupV2Controller((char*)"/sys/fs/cgroup", + (char*)"/bar" /* cgroup_path */, + controller_read_only); + EXPECT_TRUE(test->needs_hierarchy_adjustment()); + test = new CgroupV2Controller((char*)"/sys/fs/cgroup/b", + (char*)"/a/b" /* cgroup_path */, + controller_read_only); + EXPECT_TRUE(test->needs_hierarchy_adjustment()); + + CgroupCpuController* test2 = new CgroupV2CpuController(CgroupV2Controller((char*)"/sys/fs/cgroup", + (char*)"/" /* cgroup_path */, + controller_read_only)); + EXPECT_FALSE(test2->needs_hierarchy_adjustment()); + test2 = new CgroupV2CpuController(CgroupV2Controller((char*)"/sys/fs/cgroup", + (char*)"/bar" /* cgroup_path */, + controller_read_only)); + EXPECT_TRUE(test2->needs_hierarchy_adjustment()); + test2 = new CgroupV2CpuController(CgroupV2Controller((char*)"/sys/fs/cgroup/b", + (char*)"/a/b" /* cgroup_path */, + controller_read_only)); + EXPECT_TRUE(test2->needs_hierarchy_adjustment()); + + CgroupMemoryController* test3 = new CgroupV2MemoryController(CgroupV2Controller((char*)"/sys/fs/cgroup", + (char*)"/" /* cgroup_path */, + controller_read_only)); + EXPECT_FALSE(test3->needs_hierarchy_adjustment()); + test3 = new CgroupV2MemoryController(CgroupV2Controller((char*)"/sys/fs/cgroup", + (char*)"/bar" /* cgroup_path */, + controller_read_only)); + EXPECT_TRUE(test3->needs_hierarchy_adjustment()); + test3 = new CgroupV2MemoryController(CgroupV2Controller((char*)"/sys/fs/cgroup/b", + (char*)"/a/b" /* cgroup_path */, + controller_read_only)); + EXPECT_TRUE(test3->needs_hierarchy_adjustment()); +} + +TEST(cgroupTest, cgroupv1_is_hierarchy_walk_needed) { + bool controller_read_only = true; // shouldn't matter; + CgroupV1Controller* test = new CgroupV1Controller((char*)"/a/b/c" /* root */, + (char*)"/sys/fs/cgroup/memory" /* mount_path */, + controller_read_only); + test->set_subsystem_path((char*)"/a/b/c"); + EXPECT_FALSE(test->needs_hierarchy_adjustment()); + test->set_subsystem_path((char*)"/"); + EXPECT_TRUE(test->needs_hierarchy_adjustment()); + test = new CgroupV1Controller((char*)"/a/b/c" /* root */, + (char*)"/"/* mount_path */, + controller_read_only); + test->set_subsystem_path((char*)"/"); + EXPECT_TRUE(test->needs_hierarchy_adjustment()); + + CgroupCpuController* test2 = new CgroupV1CpuController(CgroupV1Controller((char*)"/a/b/c" /* root */, + (char*)"/sys/fs/cgroup/memory" /* mount_path */, + controller_read_only)); + static_cast(test2)->set_subsystem_path((char*)"/a/b/c"); + EXPECT_FALSE(test2->needs_hierarchy_adjustment()); + static_cast(test2)->set_subsystem_path((char*)"/"); + EXPECT_TRUE(test2->needs_hierarchy_adjustment()); + test2 = new CgroupV1CpuController(CgroupV1Controller((char*)"/a/b/c" /* root */, + (char*)"/"/* mount_path */, + controller_read_only)); + static_cast(test2)->set_subsystem_path((char*)"/"); + EXPECT_TRUE(test2->needs_hierarchy_adjustment()); + + CgroupMemoryController* test3 = new CgroupV1MemoryController(CgroupV1Controller((char*)"/a/b/c" /* root */, + (char*)"/sys/fs/cgroup/memory" /* mount_path */, + controller_read_only)); + static_cast(test3)->set_subsystem_path((char*)"/a/b/c"); + EXPECT_FALSE(test3->needs_hierarchy_adjustment()); + static_cast(test3)->set_subsystem_path((char*)"/"); + EXPECT_TRUE(test3->needs_hierarchy_adjustment()); + test3 = new CgroupV1MemoryController(CgroupV1Controller((char*)"/a/b/c" /* root */, + (char*)"/"/* mount_path */, + controller_read_only)); + static_cast(test3)->set_subsystem_path((char*)"/"); + EXPECT_TRUE(test3->needs_hierarchy_adjustment()); +} + #endif // LINUX diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 9d91cad1dde..384374b4f76 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -51,3 +51,5 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 829 vmTestbase/nsk/stress/thread/thread006.java 8321476 linux-all gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 + +runtime/condy/escapeAnalysis/TestEscapeCondy.java 8339694 generic-all diff --git a/test/hotspot/jtreg/ProblemList-generational-zgc.txt b/test/hotspot/jtreg/ProblemList-generational-zgc.txt index db8182641ac..801328ec4ae 100644 --- a/test/hotspot/jtreg/ProblemList-generational-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-generational-zgc.txt @@ -92,6 +92,7 @@ serviceability/sa/TestIntConstant.java 8307393 generic- serviceability/sa/TestJhsdbJstackLineNumbers.java 8307393 generic-all serviceability/sa/TestJhsdbJstackLock.java 8307393 generic-all serviceability/sa/TestJhsdbJstackMixed.java 8307393 generic-all +serviceability/sa/TestJhsdbJstackUpcall.java 8307393 generic-all serviceability/sa/TestJmapCore.java 8307393 generic-all serviceability/sa/TestJmapCoreMetaspace.java 8307393 generic-all serviceability/sa/TestObjectAlignment.java 8307393 generic-all diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 8eb3a6412c6..b80580cc6ad 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -116,7 +116,6 @@ runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all -runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/Thread/TestAlwaysPreTouchStacks.java 8335167 macosx-aarch64 runtime/cds/appcds/customLoader/HelloCustom_JFR.java 8241075 linux-all,windows-x64 diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 5f4c52186a7..74540b6ad45 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -87,6 +87,7 @@ requires.properties= \ vm.musl \ vm.flagless \ docker.support \ + systemd.support \ jdk.containerized # Minimum jtreg version diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java index f20c28e321d..1e90c22ddab 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java @@ -27,7 +27,8 @@ /* * @test - * @bug 8297384 + * @bug 8297384 8335444 + * @key randomness * @summary Test that Ideal transformations of AndINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.AndINodeIdealizationTests @@ -38,7 +39,7 @@ public static void main(String[] args) { TestFramework.run(); } - @Run(test = { "test1", "test2" }) + @Run(test = { "test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10" }) public void runMethod() { int a = RunInfo.getRandom().nextInt(); int b = RunInfo.getRandom().nextInt(); @@ -47,7 +48,12 @@ public void runMethod() { int max = Integer.MAX_VALUE; assertResult(0, 0); + assertResult(10, 20); + assertResult(10, -20); + assertResult(-10, 20); + assertResult(-10, -20); assertResult(a, b); + assertResult(b, a); assertResult(min, min); assertResult(max, max); } @@ -56,6 +62,14 @@ public void runMethod() { public void assertResult(int a, int b) { Asserts.assertEQ((0 - a) & 1, test1(a)); Asserts.assertEQ((~a) & (~b), test2(a, b)); + Asserts.assertEQ((a & 15) >= 0, test3(a, b)); + Asserts.assertEQ((a & 15) > 15, test4(a, b)); + Asserts.assertEQ((a & (b >>> 1)) >= 0, test5(a, b)); + Asserts.assertEQ((a & (b >>> 30)) > 3, test6(a, b)); + Asserts.assertEQ(((byte)a & -8) >= -128, test7(a, b)); + Asserts.assertEQ(((byte)a & -8) <= 127, test8(a, b)); + Asserts.assertEQ(((a & 255) & (char)b) > 255, test9(a, b)); + Asserts.assertEQ((((a & 1) - 3) & ((b & 2) - 10)) > -8, test10(a, b)); } @Test @@ -74,4 +88,60 @@ public int test1(int x) { public int test2(int a, int b) { return (~a) & (~b); } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & 15 => [0, 15] + public boolean test3(int a, int b) { + return (a & 15) >= 0; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & 15 => [0, 15] + public boolean test4(int a, int b) { + return (a & 15) > 15; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & [0, int_max] => [0, int_max] + public boolean test5(int a, int b) { + return (a & (b >>> 1)) >= 0; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & [0, 3] => [0, 3] + public boolean test6(int a, int b) { + return (a & (b >>> 30)) > 3; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks [-128, 127] & -8 => [-128, 127] + public boolean test7(int a, int b) { + return ((byte)a & -8) >= -128; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks [-128, 127] & -8 => [-128, 127] + public boolean test8(int a, int b) { + return ((byte)a & -8) <= 127; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks that [0, 255] & [0, 65535] => [0, 255] + public boolean test9(int a, int b) { + return ((a & 255) & (char)b) > 255; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks that [-3, -2] & [-10, -8] => [-16, -8] + public boolean test10(int a, int b) { + return (((a & 1) - 3) & ((b & 2) - 10)) > -8; + } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java index 9aa1b62be97..a32172b2015 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java @@ -27,7 +27,8 @@ /* * @test - * @bug 8322589 + * @bug 8322589 8335444 + * @key randomness * @summary Test that Ideal transformations of AndLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.AndLNodeIdealizationTests @@ -38,7 +39,7 @@ public static void main(String[] args) { TestFramework.run(); } - @Run(test = { "test1" }) + @Run(test = { "test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9" }) public void runMethod() { long a = RunInfo.getRandom().nextLong(); long b = RunInfo.getRandom().nextLong(); @@ -47,7 +48,12 @@ public void runMethod() { long max = Long.MAX_VALUE; assertResult(0, 0); + assertResult(10, 20); + assertResult(10, -20); + assertResult(-10, 20); + assertResult(-10, -20); assertResult(a, b); + assertResult(b, a); assertResult(min, min); assertResult(max, max); } @@ -55,6 +61,14 @@ public void runMethod() { @DontCompile public void assertResult(long a, long b) { Asserts.assertEQ((~a) & (~b), test1(a, b)); + Asserts.assertEQ((a & 15) >= 0, test2(a, b)); + Asserts.assertEQ((a & 15) > 15, test3(a, b)); + Asserts.assertEQ((a & (b >>> 1)) >= 0, test4(a, b)); + Asserts.assertEQ((a & (b >>> 62)) > 3, test5(a, b)); + Asserts.assertEQ(((byte)a & -8L) >= -128, test6(a, b)); + Asserts.assertEQ(((byte)a & -8L) <= 127, test7(a, b)); + Asserts.assertEQ(((a & 255) & (char)b) > 255, test8(a, b)); + Asserts.assertEQ((((a & 1) - 3) & ((b & 2) - 10)) > -8, test9(a, b)); } @Test @@ -65,4 +79,60 @@ public void assertResult(long a, long b) { public long test1(long a, long b) { return (~a) & (~b); } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & 15 => [0, 15] + public boolean test2(long a, long b) { + return (a & 15) >= 0; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & 15 => [0, 15] + public boolean test3(long a, long b) { + return (a & 15) > 15; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & [0, long_max] => [0, long_max] + public boolean test4(long a, long b) { + return (a & (b >>> 1)) >= 0; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks a & [0, 3] => [0, 3] + public boolean test5(long a, long b) { + return (a & (b >>> 62)) > 3; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks [-128, 127] & -8 => [-128, 127] + public boolean test6(long a, long b) { + return ((byte)a & -8L) >= -128; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks [-128, 127] & -8 => [-128, 127] + public boolean test7(long a, long b) { + return ((byte)a & -8L) <= 127; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks that [0, 255] & [0, 65535] => [0, 255] + public boolean test8(long a, long b) { + return ((a & 255) & (char)b) > 255; + } + + @Test + @IR(failOn = { IRNode.AND }) + // Checks that [-3, -2] & [-10, -8] => [-16, -8] + public boolean test9(long a, long b) { + return (((a & 1) - 3) & ((b & 2) - 10)) > -8; + } } diff --git a/test/hotspot/jtreg/compiler/calls/TestManyArgs.java b/test/hotspot/jtreg/compiler/calls/TestManyArgs.java new file mode 100644 index 00000000000..fbd9c13d7c9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/calls/TestManyArgs.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @summary Pass values on stack. + * @requires os.arch == "riscv64" + * @run main/native compiler.calls.TestManyArgs + */ + +package compiler.calls; + +public class TestManyArgs { + static { + System.loadLibrary("TestManyArgs"); + } + + native static void scramblestack(); + + native static int checkargs(int arg0, short arg1, byte arg2, + int arg3, short arg4, byte arg5, + int arg6, short arg7, byte arg8, + int arg9, short arg10, byte arg11); + + static int compiledbridge(int arg0, short arg1, byte arg2, + int arg3, short arg4, byte arg5, + int arg6, short arg7, byte arg8, + int arg9, short arg10, byte arg11) { + return checkargs(arg0, arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9, arg10, arg11); + } + + static public void main(String[] args) { + scramblestack(); + for (int i = 0; i < 20000; i++) { + int res = compiledbridge((int)0xf, (short)0xf, (byte)0xf, + (int)0xf, (short)0xf, (byte)0xf, + (int)0xf, (short)0xf, (byte)0xf, + (int)0xf, (short)0xf, (byte)0xf); + if (res != 0) { + throw new RuntimeException("Test failed"); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/calls/libTestManyArgs.c b/test/hotspot/jtreg/compiler/calls/libTestManyArgs.c new file mode 100644 index 00000000000..8836c79e43e --- /dev/null +++ b/test/hotspot/jtreg/compiler/calls/libTestManyArgs.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jni.h" + +#ifdef riscv64 +/* RV64 ABI pass all integers as 64-bit, in registers or on stack + * As compiler may choose to load smaller width than 64-bit if passed on stack, + * this test may not find any bugs. + * Therefore we trick the compiler todo 64-bit loads, + * by saying these args are jlongs. + */ +JNIEXPORT jint JNICALL Java_compiler_calls_TestManyArgs_checkargs(JNIEnv* env, jclass jclazz, + jlong arg0, jlong arg1, jlong arg2, + jlong arg3, jlong arg4, jlong arg5, + jlong arg6, jlong arg7, jlong arg8, + jlong arg9, jlong arg10, jlong arg11) +#else +JNIEXPORT jint JNICALL Java_compiler_calls_TestManyArgs_checkargs(JNIEnv* env, jclass jclazz, + jint arg0, jshort arg1, jbyte arg2, + jint arg3, jshort arg4, jbyte arg5, + jint arg6, jshort arg7, jbyte arg8, + jint arg9, jshort arg10, jbyte arg11) +#endif +{ + if (arg0 != 0xf) return 1; + if (arg1 != 0xf) return 1; + if (arg2 != 0xf) return 1; + if (arg3 != 0xf) return 1; + if (arg4 != 0xf) return 1; + if (arg5 != 0xf) return 1; + if (arg6 != 0xf) return 1; + if (arg7 != 0xf) return 1; + if (arg8 != 0xf) return 1; + if (arg9 != 0xf) return 1; + if (arg10 != 0xf) return 1; + if (arg11 != 0xf) return 1; + return 0; +} + +JNIEXPORT +void JNICALL Java_compiler_calls_TestManyArgs_scramblestack(JNIEnv* env, jclass jclazz) +{ + volatile char stack[12*8]; + for (unsigned int i = 0; i < sizeof(stack); i++) { + stack[i] = (char)0xff; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/LongCountedLoopInInfiniteLoop.jasm b/test/hotspot/jtreg/compiler/loopopts/LongCountedLoopInInfiniteLoop.jasm new file mode 100644 index 00000000000..e7f75d46b5b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/LongCountedLoopInInfiniteLoop.jasm @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, 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. + */ + +super public class LongCountedLoopInInfiniteLoop +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + Method test:"()V" + stack 3 locals 3 + { + // #1 = 0; + iconst_0; + istore_1; + + LOOPa: + // if #1 >= 10: goto END + iload_1; + bipush 10; + if_icmpge END; + + // if #1 > 1: goto LOOPc + iload_1; + iconst_1; + if_icmpgt LOOPc; + + // #2 = 0; + iconst_0; + istore_2; + + LOOPb: + // if #2 > 2: goto LOOPa + iload_2; + iconst_2; + if_icmpgt LOOPa; + + // #2 ++ + iinc 2, 1; + + goto LOOPb; + + LOOPc: + // #1 ++ + iinc 1, 1; + + goto LOOPa; + + END: + return; + + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/MoveStoreAfterInfiniteLoop.jasm b/test/hotspot/jtreg/compiler/loopopts/MoveStoreAfterInfiniteLoop.jasm new file mode 100644 index 00000000000..f93a2aa1170 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/MoveStoreAfterInfiniteLoop.jasm @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024, 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. + */ + +super public class MoveStoreAfterInfiniteLoop +{ + static Field a:I; + static Field b:I; + static Field c:S; + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + +public static Method test:"()V" + stack 3 locals 3 + { + LTOP: + iconst_0; + istore_1; + + LOUTER: + iload_1; + bipush 10; + if_icmpge LTOP; + + getstatic Field c:"S"; + putstatic Field a:"I"; + + iconst_0; + istore_2; + + LINNER: + iload_2; + iconst_2; + if_icmpge LBOTTOM; + + getstatic Field b:"I"; + i2s; + putstatic Field c:"S"; + + iinc 2, 1; + + goto LINNER; + + LBOTTOM: + iinc 1, 1; + + goto LOUTER; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestLongCountedLoopInInfiniteLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestLongCountedLoopInInfiniteLoop.java new file mode 100644 index 00000000000..4dc16797258 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestLongCountedLoopInInfiniteLoop.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8336478 + * @summary C2: assert(!n->as_Loop()->is_loop_nest_inner_loop() || _loop_opts_cnt == 0) failed: should have been turned into a counted loop + * @compile LongCountedLoopInInfiniteLoop.jasm + * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xcomp -XX:PerMethodTrapLimit=0 -XX:PerMethodSpecTrapLimit=0 + * -XX:+IgnoreUnrecognizedVMOptions -XX:StressLongCountedLoop=2000000 + * -XX:CompileCommand=compileonly,TestLongCountedLoopInInfiniteLoop::test TestLongCountedLoopInInfiniteLoop + */ + +public class TestLongCountedLoopInInfiniteLoop { + public static void main(String[] args) { + LongCountedLoopInInfiniteLoop obj = new LongCountedLoopInInfiniteLoop(); + test(false, obj); + } + + private static void test(boolean flag, LongCountedLoopInInfiniteLoop obj) { + if (flag) { + obj.test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestMoveStoreAfterInfiniteLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestMoveStoreAfterInfiniteLoop.java new file mode 100644 index 00000000000..322e7a5053c --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestMoveStoreAfterInfiniteLoop.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338100 + * @summary C2: assert(!n_loop->is_member(get_loop(lca))) failed: control must not be back in the loop + * @compile MoveStoreAfterInfiniteLoop.jasm + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestMoveStoreAfterInfiniteLoop::test + * -XX:CompileCommand=inline,MoveStoreAfterInfiniteLoop::test TestMoveStoreAfterInfiniteLoop + */ + +public class TestMoveStoreAfterInfiniteLoop { + public static void main(String[] args) { + new MoveStoreAfterInfiniteLoop(); + test(false); + } + + private static void test(boolean flag) { + if (flag) { + MoveStoreAfterInfiniteLoop.test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java index d1a61538f2e..bb6185177e7 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. + * Copyright (c) 2024, 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 @@ -71,12 +72,9 @@ public boolean[] vectorNot() { } @Test - @IR(applyIfCPUFeature = {"asimd", "true"}, - counts = {IRNode.AND_VB, ">0"}) - @IR(applyIfCPUFeatureAnd = {"avx512f", "false", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION, counts = {IRNode.AND_VB, ">0"}) - @IR(applyIfCPUFeature = {"avx512f", "true"}, - counts = {IRNode.MACRO_LOGIC_V, ">0"}) public boolean[] vectorAnd() { boolean[] res = new boolean[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/containers/systemd/HelloSystemd.java b/test/hotspot/jtreg/containers/systemd/HelloSystemd.java new file mode 100644 index 00000000000..1b320131bf5 --- /dev/null +++ b/test/hotspot/jtreg/containers/systemd/HelloSystemd.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * 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. + */ + +public class HelloSystemd { + public static void main(String args[]) { + System.out.println("Hello Systemd"); + } +} diff --git a/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java b/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java new file mode 100644 index 00000000000..2c06d48bb1c --- /dev/null +++ b/test/hotspot/jtreg/containers/systemd/SystemdMemoryAwarenessTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * 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 jdk.test.lib.containers.systemd.SystemdRunOptions; +import jdk.test.lib.containers.systemd.SystemdTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.whitebox.WhiteBox; +import jtreg.SkippedException; + +/* + * @test + * @bug 8322420 8217338 + * @summary Memory/CPU awareness test for JDK-under-test inside a systemd slice. + * @requires systemd.support + * @library /test/lib + * @modules java.base/jdk.internal.platform + * @build HelloSystemd jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:whitebox.jar -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SystemdMemoryAwarenessTest + */ +public class SystemdMemoryAwarenessTest { + + private static final int MB = 1024 * 1024; + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + private static final String TEST_SLICE_NAME = SystemdMemoryAwarenessTest.class.getSimpleName() + "HS"; + + public static void main(String[] args) throws Exception { + testHelloSystemd(); + } + + private static void testHelloSystemd() throws Exception { + SystemdRunOptions opts = SystemdTestUtils.newOpts("HelloSystemd"); + // 1 GB memory, but the limit in the lower hierarchy is 512M + opts.memoryLimit("1024M"); + int expectedMemLimit = 512; + // expected detected limit we test for, 512MB + opts.sliceDMemoryLimit(String.format("%dM", expectedMemLimit)); + int physicalCpus = wb.hostCPUs(); + if (physicalCpus < 2) { + System.err.println("WARNING: host system only has " + physicalCpus + " cpus. Expected >= 2"); + System.err.println("The active_processor_count assertion will trivially pass."); + } + // Use a CPU core limit of 1 for best coverage + int coreLimit = 1; + System.out.println("DEBUG: Running test with a CPU limit of " + coreLimit); + opts.cpuLimit(String.format("%d%%", coreLimit * 100)); + opts.sliceName(TEST_SLICE_NAME); + + OutputAnalyzer out = SystemdTestUtils.buildAndRunSystemdJava(opts); + out.shouldHaveExitValue(0) + .shouldContain("Hello Systemd") + .shouldContain(String.format("Memory Limit is: %d", (expectedMemLimit * MB))); + try { + out.shouldContain("OSContainer::active_processor_count: " + coreLimit); + } catch (RuntimeException e) { + // CPU delegation needs to be enabled when run as user on cg v2 + if (SystemdTestUtils.RUN_AS_USER) { + String hint = "When run as user on cg v2 cpu delegation needs to be configured!"; + throw new SkippedException(hint); + } + throw e; + } + } + +} diff --git a/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java b/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java index 598633d307f..6ed778e6e0b 100644 --- a/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java +++ b/test/hotspot/jtreg/resourcehogs/compiler/intrinsics/string/TestStringIntrinsics2LargeArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -35,7 +35,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * * @run main/othervm - * -mx8G + * -Xmx8G * -Xbootclasspath/a:. * -Xmixed * -XX:+UnlockDiagnosticVMOptions diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java index 80ded6f898d..00b5becdbfa 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java @@ -22,7 +22,7 @@ */ /* - * @test id=checkDecoder + * @test * @bug 8242181 * @library / /test/lib * @summary Test DWARF parser with various crashes if debug symbols are available. If the libjvm debug symbols are not @@ -30,15 +30,7 @@ * by the environment variable _JVM_DWARF_PATH, then no verification of the hs_err_file is done for libjvm.so. * @requires vm.debug == true & vm.flagless & vm.compMode != "Xint" & os.family == "linux" & !vm.graal.enabled & vm.gc.G1 * @modules java.base/jdk.internal.misc - * @run main/native/othervm -Xbootclasspath/a:. -XX:-CreateCoredumpOnCrash -DcheckDecoder=true TestDwarf - */ - -/* - * @test id=dontCheckDecoder - * @library / /test/lib - * @requires vm.debug == true & vm.flagless & vm.compMode != "Xint" & os.family == "linux" & !vm.graal.enabled & vm.gc.G1 - * @modules java.base/jdk.internal.misc - * @run main/native/othervm -Xbootclasspath/a:. -XX:-CreateCoredumpOnCrash -DcheckDecoder=false TestDwarf + * @run main/native/othervm -Xbootclasspath/a:. -XX:-CreateCoredumpOnCrash TestDwarf */ import jdk.test.lib.Asserts; @@ -63,8 +55,6 @@ public class TestDwarf { System.loadLibrary("TestDwarf"); } - static boolean checkDecoder = Boolean.getBoolean("checkDecoder"); - public static void main(String[] args) throws Exception { if (args.length != 0) { switch (args[0]) { @@ -127,11 +117,11 @@ private static void test() throws Exception { new DwarfConstraint(0, "dereference_null", "libTestDwarfHelper.h", 46)); } - // The full pattern accepts lines like: + // A full pattern could check for lines like: // V [libjvm.so+0x8f4ed8] report_fatal(VMErrorType, char const*, int, char const*, ...)+0x78 (debug.cpp:212) - // but if the decoder is not available we only get + // but the decoder is not reliably working at the moment (see JDK-8305489). We therefore use a pattern that only + // checks that lines have the following structure with source information: // V [libjvm.so+0x8f4ed8] (debug.cpp:212) - private static final String FULL_PATTERN ="[CV][\\s\\t]+\\[([a-zA-Z0-9_.]+)\\+0x.+][\\s\\t]+.*\\+0x.+[\\s\\t]+\\([a-zA-Z0-9_.]+\\.[a-z]+:[1-9][0-9]*\\)"; private static final String NO_DECODER_PATTERN ="[CV][\\s\\t]+\\[([a-zA-Z0-9_.]+)\\+0x.+].*\\([a-zA-Z0-9_.]+\\.[a-z]+:[1-9][0-9]*\\)"; private static void runAndCheck(Flags flags, DwarfConstraint... constraints) throws Exception { @@ -149,7 +139,7 @@ private static void runAndCheck(Flags flags, DwarfConstraint... constraints) thr int matches = 0; int frameIdx = 0; - Pattern pattern = Pattern.compile(checkDecoder ? FULL_PATTERN : NO_DECODER_PATTERN); + Pattern pattern = Pattern.compile(NO_DECODER_PATTERN); // Check all stack entries after the line starting with "Native frames" in the hs_err_file until an empty line // is found which denotes the end of the stack frames. @@ -202,14 +192,6 @@ private static void checkMissingElement(String crashOutputString, String line) { pattern = Pattern.compile("Failed to load DWARF file for library.*" + library + ".*or find DWARF sections directly inside it"); matcher = pattern.matcher(crashOutputString); if (!matcher.find()) { - // Symbols were fine so check if we expected decoder output and didn't find it. - if (checkDecoder) { - pattern = Pattern.compile(NO_DECODER_PATTERN); - matcher = pattern.matcher(line); - if (matcher.find()) { - Asserts.fail("Could not find decoded method signature in \"" + line + "\""); - } - } bailoutIfUnsupportedDwarfVersion(crashOutputString); Asserts.fail("Could not find filename or line number in \"" + line + "\""); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/StaticArchiveWithLambda.java b/test/hotspot/jtreg/runtime/cds/appcds/StaticArchiveWithLambda.java index 67530467cf8..9bab98a5d2c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/StaticArchiveWithLambda.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/StaticArchiveWithLambda.java @@ -52,7 +52,8 @@ public static void main(String[] args) throws Exception { "-cp", appJar, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + CDSTestUtils.createArchiveAndCheck(opts) + .shouldContain("Skipping java/lang/invoke/BoundMethodHandle$Species_LLLL because it is dynamically generated"); // run with archive CDSOptions runOpts = (new CDSOptions()) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java index 74ddfcebe1b..7d68fdf0fc8 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java @@ -76,7 +76,6 @@ public static void main(String[] args) throws Throwable { output.shouldContain(warningMessages[0]); output.shouldContain(warningMessages[1]); output.shouldContain("inside SimpleAgent"); - output.shouldContain("Skipping java/lang/invoke/BoundMethodHandle$Species_LLLL because it is dynamically generated"); // CDS dumping with a java agent with the AllowArchvingWithJavaAgent diagnostic option. output = TestCommon.testDump(appJar, TestCommon.list("Hello"), diff --git a/test/hotspot/jtreg/runtime/condy/BadBSMUseTest.java b/test/hotspot/jtreg/runtime/condy/BadBSMUseTest.java index a07c98caa66..3e36d1aebd9 100644 --- a/test/hotspot/jtreg/runtime/condy/BadBSMUseTest.java +++ b/test/hotspot/jtreg/runtime/condy/BadBSMUseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 8186211 * @summary CONSTANT_Dynamic_info structure's tries to use a BSM index whose signature is for an invokedynamic and vice versa. - * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib * @compile CondyUsesIndyBSM.jcod @@ -42,7 +41,7 @@ public class BadBSMUseTest { public static void main(String args[]) throws Throwable { // 1. Test a CONSTANT_Dynamic_info's bootstrap_method_attr_index points // at a BSM meant for a CONSTANT_InvokeDynamic_info - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("CondyUsesIndyBSM"); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("CondyUsesIndyBSM"); OutputAnalyzer oa = new OutputAnalyzer(pb.start()); oa.shouldContain("In Indybsm target CallSite method foo"); oa.shouldContain("BootstrapMethodError: bootstrap method initialization exception"); @@ -50,7 +49,7 @@ public static void main(String args[]) throws Throwable { // 2. Test a CONSTANT_InvokeDynamic_info's bootstrap_method_attr_index points // at a BSM meant for a CONSTANT_Dynamic_info - pb = ProcessTools.createLimitedTestJavaProcessBuilder("IndyUsesCondyBSM"); + pb = ProcessTools.createTestJavaProcessBuilder("IndyUsesCondyBSM"); oa = new OutputAnalyzer(pb.start()); oa.shouldContain("In Condybsm"); oa.shouldContain("BootstrapMethodError: bootstrap method initialization exception"); diff --git a/test/hotspot/jtreg/runtime/condy/CondyExtendedNullPointer.jasm b/test/hotspot/jtreg/runtime/condy/CondyExtendedNullPointer.jasm new file mode 100644 index 00000000000..7697b0c46da --- /dev/null +++ b/test/hotspot/jtreg/runtime/condy/CondyExtendedNullPointer.jasm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, 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. + */ + +/* + * This test generates an extended NullPointerException inside a method with + * a condy ldc. We add two ldc instructions and a pop around the real null + * value to stress the stack handling of the NPE message generator. + */ +class CondyExtendedNullPointer + version 55:0 +{ + +static Field nullObject:"Ljava/lang/Object;"; + +public static Method condy:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)I" + stack 1 locals 3 +{ + bipush 123; + ireturn; +} + +public static Method main:"([Ljava/lang/String;)V" + stack 3 locals 1 +{ + ldc Dynamic REF_invokeStatic:CondyExtendedNullPointer.condy:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)I":I:"I"; + getstatic Field nullObject:"Ljava/lang/Object;"; + ldc Dynamic REF_invokeStatic:CondyExtendedNullPointer.condy:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)I":I:"I"; + pop; + invokevirtual Method java/lang/Object.notify:"()V"; + return; +} + +} // end Class CondyExtendedNullPointer diff --git a/test/hotspot/jtreg/runtime/condy/CondyExtendedNullPointerTest.java b/test/hotspot/jtreg/runtime/condy/CondyExtendedNullPointerTest.java new file mode 100644 index 00000000000..665633796f6 --- /dev/null +++ b/test/hotspot/jtreg/runtime/condy/CondyExtendedNullPointerTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 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 8339488 + * @summary Test extended NullPointerException message in method with CONSTANT_Dynamic. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @compile CondyExtendedNullPointer.jasm + * @run driver CondyExtendedNullPointerTest + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class CondyExtendedNullPointerTest { + public static void main(String args[]) throws Throwable { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", + "CondyExtendedNullPointer"); + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + oa.shouldContain("Cannot invoke \"Object.notify()\" because \"CondyExtendedNullPointer.nullObject\" is null"); + oa.shouldHaveExitValue(1); + } +} diff --git a/test/hotspot/jtreg/runtime/condy/CondyLDCTest.java b/test/hotspot/jtreg/runtime/condy/CondyLDCTest.java index 22cfb727eb8..1b045d1e36e 100644 --- a/test/hotspot/jtreg/runtime/condy/CondyLDCTest.java +++ b/test/hotspot/jtreg/runtime/condy/CondyLDCTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 8186211 * @summary Tests various ldc, ldc_w, ldc2_w instructions of CONSTANT_Dynamic. - * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib * @compile CondyUseLDC_W.jasm @@ -42,7 +41,7 @@ public class CondyLDCTest { public static void main(String args[]) throws Throwable { // 1. Test a ldc_w instruction can be used with condy's which generate // loadable constants of the following types: byte, char, short, float, integer, boolean. - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xverify:all", + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", "CondyUseLDC_W"); OutputAnalyzer oa = new OutputAnalyzer(pb.start()); oa.shouldNotContain("VerifyError"); @@ -50,7 +49,7 @@ public static void main(String args[]) throws Throwable { // 2. Test ldc2_w of a condy which returns a dynamically generated // float constant, generates a VerifyError. - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xverify:all", + pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", "CondyBadLDC2_W"); oa = new OutputAnalyzer(pb.start()); oa.shouldContain("java.lang.VerifyError: Illegal type at constant pool entry"); @@ -59,7 +58,7 @@ public static void main(String args[]) throws Throwable { // 3. Test a ldc of a condy which returns a dynamically generated // double constant, generates a VerifyError. - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xverify:all", + pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", "CondyBadLDC"); oa = new OutputAnalyzer(pb.start()); oa.shouldContain("java.lang.VerifyError: Illegal type at constant pool entry"); diff --git a/test/hotspot/jtreg/runtime/condy/CondyNewInvokeSpecialTest.java b/test/hotspot/jtreg/runtime/condy/CondyNewInvokeSpecialTest.java index 6e810d0d3b8..ddada0edbf7 100644 --- a/test/hotspot/jtreg/runtime/condy/CondyNewInvokeSpecialTest.java +++ b/test/hotspot/jtreg/runtime/condy/CondyNewInvokeSpecialTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 8186211 * @summary Test CONSTANT_Dynamic where the BSM is invoked via a REF_newInvokeSpecial. - * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib * @compile CondyNewInvokeSpecial.jasm @@ -38,7 +37,7 @@ public class CondyNewInvokeSpecialTest { public static void main(String args[]) throws Throwable { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xverify:all", + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Xverify:all", "CondyNewInvokeSpecial"); OutputAnalyzer oa = new OutputAnalyzer(pb.start()); oa.shouldContain("In CondyNewInvokeSpecial method"); diff --git a/test/hotspot/jtreg/runtime/condy/escapeAnalysis/TestEscapeCondy.java b/test/hotspot/jtreg/runtime/condy/escapeAnalysis/TestEscapeCondy.java index 877a805c445..a90b987db14 100644 --- a/test/hotspot/jtreg/runtime/condy/escapeAnalysis/TestEscapeCondy.java +++ b/test/hotspot/jtreg/runtime/condy/escapeAnalysis/TestEscapeCondy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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,6 @@ * @bug 8216970 * @summary Ensure escape analysis can handle an ldc of a dynamic * constant whose return type is an array of boolean. - * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib * @compile TestEscapeThroughInvokeWithCondy$A.jasm @@ -43,7 +42,7 @@ public class TestEscapeCondy { public static void main(String args[]) throws Throwable { // 1. Test escape analysis of a method that contains // a ldc instruction of a condy whose return type is an array of boolean - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:CompileCommand=dontinline,runtime.condy.TestEscapeThroughInvokeWithCondy::create", "runtime.condy.TestEscapeThroughInvokeWithCondy"); OutputAnalyzer oa = new OutputAnalyzer(pb.start()); diff --git a/test/hotspot/jtreg/runtime/condy/staticInit/TestInitException.java b/test/hotspot/jtreg/runtime/condy/staticInit/TestInitException.java index 2b572edb66f..412a1639e69 100644 --- a/test/hotspot/jtreg/runtime/condy/staticInit/TestInitException.java +++ b/test/hotspot/jtreg/runtime/condy/staticInit/TestInitException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ * @test * @bug 8228485 * @summary Correctly handle initialization error for Condy BSM. - * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib * @compile Example.jasm @@ -38,7 +37,7 @@ public class TestInitException { public static void main(java.lang.String[] unused) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("Example"); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("Example"); OutputAnalyzer oa = new OutputAnalyzer(pb.start()); // First call stack trace // shouldMatch is used to workaround CODETOOLS-7902686 @@ -52,4 +51,3 @@ public static void main(java.lang.String[] unused) throws Exception { oa.shouldHaveExitValue(1); } } - diff --git a/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java b/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java index 2d23358e96b..09646d07358 100644 --- a/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/reflect/ReflectOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -88,15 +88,24 @@ public static void main(java.lang.String[] unused) throws Exception { Object junk = testMethod.invoke(null, new Object [0]); throw new RuntimeException("InvocationTargetException should be thrown"); } catch (InvocationTargetException ite) { - Throwable targetException = ite.getTargetException(); - if (targetException instanceof OutOfMemoryError) { - System.out.println("OutOfMemoryError thrown as expected."); - System.out.println("Test passed."); - } else { - throw new RuntimeException("Unexpected InvocationTargetException: " + targetException); + // We may not directly get OOME but it could have caused + // secondary exceptions, so walk the chain of exceptions + // and see if there is an OOME somewhere. + for (Throwable cause = ite.getTargetException(); + cause != null; + cause = cause.getCause()) { + if (cause instanceof OutOfMemoryError) { + System.out.println("OutOfMemoryError thrown as expected."); + ite.printStackTrace(System.out); + System.out.println("Test passed."); + return; + } } + + throw new RuntimeException("Unexpected InvocationTargetException: ", + ite.getTargetException()); } catch (Exception exception) { - throw new RuntimeException("Unexpected exception: " + exception); + throw new RuntimeException("Unexpected exception: ", exception); } } } diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java index cc8f5638c76..9ec9ca1b8c2 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/GetThreadState/GetThreadStateTest.java @@ -25,7 +25,7 @@ * @test id=default * @bug 8312498 * @summary Basic test for JVMTI GetThreadState with virtual threads - * @modules java.base/java.lang:+open + * @modules jdk.management * @library /test/lib * @run junit/othervm/native --enable-native-access=ALL-UNNAMED GetThreadStateTest */ @@ -33,7 +33,7 @@ /* * @test id=no-vmcontinuations * @requires vm.continuations - * @modules java.base/java.lang:+open + * @modules jdk.management * @library /test/lib * @run junit/othervm/native -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations --enable-native-access=ALL-UNNAMED GetThreadStateTest */ @@ -42,7 +42,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management import jdk.test.lib.thread.VThreadPinner; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/VThreadEventTest.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/VThreadEventTest.java index 845e9adba01..5b4f6ac2a48 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/VThreadEventTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/VThreadEventTest/VThreadEventTest.java @@ -28,7 +28,7 @@ * @requires vm.continuations * @requires vm.jvmti * @requires vm.compMode != "Xcomp" - * @modules java.base/java.lang:+open + * @modules jdk.management * @library /test/lib * @run main/othervm/native * -Djdk.attach.allowAttachSelf=true -XX:+EnableDynamicAgentLoading VThreadEventTest attach diff --git a/test/hotspot/jtreg/serviceability/sa/LingeredAppWithFFMUpcall.java b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithFFMUpcall.java new file mode 100644 index 00000000000..d2977c491ab --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithFFMUpcall.java @@ -0,0 +1,75 @@ + +/* + * Copyright (c) 2024, 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.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.util.concurrent.CountDownLatch; + +import jdk.test.lib.apps.LingeredApp; + +public class LingeredAppWithFFMUpcall extends LingeredApp { + + public static final String THREAD_NAME = "Upcall thread"; + + private static final Object lockObj = new Object(); + + private static final CountDownLatch signal = new CountDownLatch(1); + + static { + System.loadLibrary("upcall"); + } + + public static void upcall() { + signal.countDown(); + synchronized(lockObj) { + } + } + + public static long createFunctionPointerForUpcall() throws NoSuchMethodException, IllegalAccessException { + var mh = MethodHandles.lookup() + .findStatic(LingeredAppWithFFMUpcall.class, "upcall", MethodType.methodType(void.class)); + var stub = Linker.nativeLinker() + .upcallStub(mh, FunctionDescriptor.ofVoid(), Arena.global()); + return stub.address(); + } + + public static native void callJNI(long upcallAddr); + + public static void main(String[] args) { + try { + long upcallAddr = createFunctionPointerForUpcall(); + var upcallThread = new Thread(() -> callJNI(upcallAddr), THREAD_NAME); + synchronized(lockObj) { + upcallThread.start(); + signal.await(); + LingeredApp.main(args); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackUpcall.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackUpcall.java new file mode 100644 index 00000000000..924f56c9b44 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackUpcall.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024, 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 jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.SA.SATestUtils; +import jdk.test.lib.Utils; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.OutputAnalyzer; + +/** + * @test + * @bug 8339307 + * @requires vm.hasSA + * @library /test/lib + * @run driver TestJhsdbJstackUpcall + */ +public class TestJhsdbJstackUpcall { + + private static void runJstack(LingeredApp app) throws Exception { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + launcher.addVMArgs(Utils.getTestJavaOpts()); + launcher.addToolArg("jstack"); + launcher.addToolArg("--pid"); + launcher.addToolArg(Long.toString(app.getPid())); + + ProcessBuilder pb = SATestUtils.createProcessBuilder(launcher); + Process jhsdb = pb.start(); + OutputAnalyzer out = new OutputAnalyzer(jhsdb); + + jhsdb.waitFor(); + + System.out.println(out.getStdout()); + System.err.println(out.getStderr()); + + out.shouldContain(LingeredAppWithFFMUpcall.THREAD_NAME); + out.shouldContain("LingeredAppWithFFMUpcall.upcall()"); + out.shouldContain("jdk.internal.foreign.abi.UpcallStub"); + out.shouldContain("LingeredAppWithFFMUpcall.callJNI"); + } + + public static void main(String... args) throws Exception { + SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. + LingeredApp app = null; + + try { + // Needed for LingeredAppWithFFMUpcall to be able to resolve native library. + String libPath = System.getProperty("java.library.path"); + String[] vmArgs = (libPath != null) + ? Utils.prependTestJavaOpts("-Djava.library.path=" + libPath) + : Utils.getTestJavaOpts(); + + app = new LingeredAppWithFFMUpcall(); + LingeredApp.startAppExactJvmOpts(app, vmArgs); + System.out.println("Started LingeredAppWithFFMUpcall with pid " + app.getPid()); + runJstack(app); + System.out.println("Test Completed"); + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } finally { + LingeredApp.stopApp(app); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/sa/libupcall.c b/test/hotspot/jtreg/serviceability/sa/libupcall.c new file mode 100644 index 00000000000..2139e717fef --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/libupcall.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, 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. + */ + +#include + +typedef void (*upcall_func)(void); + +JNIEXPORT void JNICALL +Java_LingeredAppWithFFMUpcall_callJNI(JNIEnv *env, jclass cls, jlong upcallAddr) { + upcall_func upcall = (upcall_func)upcallAddr; + upcall(); +} diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java index c74c01f1bf7..61ec487c7ff 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,6 @@ package jdk.test.lib.jittester; -import jdk.test.lib.util.Pair; -import jdk.test.lib.jittester.factories.IRNodeBuilder; -import jdk.test.lib.jittester.types.TypeKlass; -import jdk.test.lib.jittester.utils.FixedTrees; -import jdk.test.lib.jittester.utils.OptionResolver; -import jdk.test.lib.jittester.utils.OptionResolver.Option; -import jdk.test.lib.jittester.utils.PseudoRandom; import java.time.LocalTime; import java.util.ArrayList; import java.util.List; @@ -39,57 +32,6 @@ public class Automatic { public static final int MINUTES_TO_WAIT = Integer.getInteger("jdk.test.lib.jittester", 3); - private static Pair generateIRTree(String name) { - ProductionLimiter.resetTimer(); - SymbolTable.removeAll(); - TypeList.removeAll(); - - IRNodeBuilder builder = new IRNodeBuilder() - .setPrefix(name) - .setName(name) - .setLevel(0); - - Long complexityLimit = ProductionParams.complexityLimit.value(); - IRNode privateClasses = null; - if (!ProductionParams.disableClasses.value()) { - long privateClassComlexity = (long) (complexityLimit * PseudoRandom.random()); - try { - privateClasses = builder.setComplexityLimit(privateClassComlexity) - .getClassDefinitionBlockFactory() - .produce(); - } catch (ProductionFailedException ex) { - ex.printStackTrace(System.out); - } - } - long mainClassComplexity = (long) (complexityLimit * PseudoRandom.random()); - IRNode mainClass = null; - try { - mainClass = builder.setComplexityLimit(mainClassComplexity) - .getMainKlassFactory() - .produce(); - TypeKlass aClass = new TypeKlass(name); - mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, true)); - mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, false)); - } catch (ProductionFailedException ex) { - ex.printStackTrace(System.out); - } - return new Pair<>(mainClass, privateClasses); - } - - private static void initializeTestGenerator(String[] params) { - OptionResolver parser = new OptionResolver(); - Option propertyFileOpt = parser.addStringOption('p', "property-file", - "conf/default.properties", "File to read properties from"); - ProductionParams.register(parser); - parser.parse(params, propertyFileOpt); - PseudoRandom.reset(ProductionParams.seed.value()); - TypesParser.parseTypesAndMethods(ProductionParams.classesFile.value(), - ProductionParams.excludeMethodsFile.value()); - if (ProductionParams.specificSeed.isSet()) { - PseudoRandom.setCurrentSeed(ProductionParams.specificSeed.value()); - } - } - private static List getTestGenerators() { List result = new ArrayList<>(); Class factoryClass; @@ -109,7 +51,9 @@ private static List getTestGenerators() { } public static void main(String[] args) { - initializeTestGenerator(args); + ProductionParams.initializeFromCmdline(args); + IRTreeGenerator.initializeWithProductionParams(); + int counter = 0; System.out.printf("Generating %d tests...%n", ProductionParams.numberOfTests.value()); System.out.printf(" %13s | %8s | %8s | %8s |%n", "start time", "count", "generat", @@ -121,7 +65,7 @@ public static void main(String[] args) { try { System.out.print("[" + LocalTime.now() + "] |"); String name = "Test_" + counter; - Pair irTree = generateIRTree(name); + var test = IRTreeGenerator.generateIRTree(name); System.out.printf(" %8d |", counter); long maxWaitTime = TimeUnit.MINUTES.toMillis(MINUTES_TO_WAIT); double generationTime = System.currentTimeMillis() - start; @@ -129,7 +73,7 @@ public static void main(String[] args) { start = System.currentTimeMillis(); Thread generatorThread = new Thread(() -> { for (TestsGenerator generator : generators) { - generator.accept(irTree.first, irTree.second); + generator.accept(test); } }); generatorThread.start(); diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java index 87ca48c5acb..fac88a1833e 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, 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 @@ -47,16 +47,17 @@ class ByteCodeGenerator extends TestsGenerator { } @Override - public void accept(IRNode mainClass, IRNode privateClasses) { - generateClassFiles(mainClass, privateClasses); - generateSeparateJtregHeader(mainClass); + public void accept(IRTreeGenerator.Test test) { + IRNode mainClass = test.mainClass(); + generateClassFiles(mainClass, test.privateClasses()); + generateSeparateJtregHeader(test.seed(), mainClass); compilePrinter(); generateGoldenOut(mainClass.getName()); } - private void generateSeparateJtregHeader(IRNode mainClass) { + private void generateSeparateJtregHeader(long seed, IRNode mainClass) { String mainClassName = mainClass.getName(); - writeFile(generatorDir, mainClassName + ".java", getJtregHeader(mainClassName)); + writeFile(generatorDir, mainClassName + ".java", getJtregHeader(mainClassName, seed)); } private void generateClassFiles(IRNode mainClass, IRNode privateClasses) { @@ -94,4 +95,17 @@ private void writeFile(String fileName, byte[] bytecode) { ex.printStackTrace(); } } + + public static void main(String[] args) throws Exception { + ProductionParams.initializeFromCmdline(args); + IRTreeGenerator.initializeWithProductionParams(); + + ByteCodeGenerator generator = new ByteCodeGenerator(); + + for (String mainClass : ProductionParams.mainClassNames.value()) { + var test = IRTreeGenerator.generateIRTree(mainClass); + generator.generateClassFiles(test.mainClass(), test.privateClasses()); + generator.generateSeparateJtregHeader(test.seed(), test.mainClass()); + } + } } diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/IRTreeGenerator.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/IRTreeGenerator.java new file mode 100644 index 00000000000..b748fadde59 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/IRTreeGenerator.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.jittester; + +import jdk.test.lib.jittester.factories.IRNodeBuilder; +import jdk.test.lib.jittester.types.TypeKlass; +import jdk.test.lib.jittester.utils.FixedTrees; +import jdk.test.lib.jittester.utils.PseudoRandom; + +/** + * Generates IR trees for fuzzy test classes. + */ +public class IRTreeGenerator { + + /** + * Generated Test - main and private classes trees along with random seed used for generation. + */ + public record Test (long seed, IRNode mainClass, IRNode privateClasses) {}; + + /** + * Generates IR trees for main and private classes. + * + * @param name main class name + * @return a pair (main class; private classes) + */ + public static Test generateIRTree(String name) { + long seed = PseudoRandom.getCurrentSeed(); + ProductionLimiter.resetTimer(); + //NB: SymbolTable is a widely-used singleton, hence all the locking. + SymbolTable.removeAll(); + TypeList.removeAll(); + + IRNodeBuilder builder = new IRNodeBuilder() + .setPrefix(name) + .setName(name) + .setLevel(0); + + Long complexityLimit = ProductionParams.complexityLimit.value(); + IRNode privateClasses = null; + if (!ProductionParams.disableClasses.value()) { + long privateClassComlexity = (long) (complexityLimit * PseudoRandom.random()); + try { + privateClasses = builder.setComplexityLimit(privateClassComlexity) + .getClassDefinitionBlockFactory() + .produce(); + } catch (ProductionFailedException ex) { + ex.printStackTrace(System.out); + } + } + long mainClassComplexity = (long) (complexityLimit * PseudoRandom.random()); + IRNode mainClass = null; + try { + mainClass = builder.setComplexityLimit(mainClassComplexity) + .getMainKlassFactory() + .produce(); + TypeKlass aClass = new TypeKlass(name); + mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, true)); + mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, false)); + } catch (ProductionFailedException ex) { + ex.printStackTrace(System.out); + } + return new Test(seed, mainClass, privateClasses); + } + + /** + * Initializes the generator from ProductionParams static class. + */ + public static void initializeWithProductionParams() { + TypesParser.parseTypesAndMethods(ProductionParams.classesFile.value(), + ProductionParams.excludeMethodsFile.value()); + if (ProductionParams.specificSeed.isSet()) { + PseudoRandom.setCurrentSeed(ProductionParams.specificSeed.value()); + } + } + +} diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java index 7ca940fe531..16d02f91d8e 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java @@ -42,19 +42,20 @@ public class JavaCodeGenerator extends TestsGenerator { } @Override - public void accept(IRNode mainClass, IRNode privateClasses) { + public void accept(IRTreeGenerator.Test test) { + IRNode mainClass = test.mainClass(); String mainClassName = mainClass.getName(); - generateSources(mainClass, privateClasses); + generateSources(test.seed(), mainClass, test.privateClasses()); compilePrinter(); compileJavaFile(mainClassName); generateGoldenOut(mainClassName); } - private void generateSources(IRNode mainClass, IRNode privateClasses) { + private void generateSources(long seed, IRNode mainClass, IRNode privateClasses) { String mainClassName = mainClass.getName(); StringBuilder code = new StringBuilder(); JavaCodeVisitor vis = new JavaCodeVisitor(); - code.append(getJtregHeader(mainClassName)); + code.append(getJtregHeader(mainClassName, seed)); if (privateClasses != null) { code.append(privateClasses.accept(vis)); } @@ -79,7 +80,19 @@ private void compileJavaFile(String mainClassName) { } } - private static String[] generatePrerunAction(String mainClassName) { + protected static String[] generatePrerunAction(String mainClassName) { return new String[] {"@compile " + mainClassName + ".java"}; } + + public static void main(String[] args) throws Exception { + ProductionParams.initializeFromCmdline(args); + IRTreeGenerator.initializeWithProductionParams(); + + JavaCodeGenerator generator = new JavaCodeGenerator(); + + for (String mainClass : ProductionParams.mainClassNames.value()) { + var test = IRTreeGenerator.generateIRTree(mainClass); + generator.generateSources(test.seed(), test.mainClass(), test.privateClasses()); + } + } } diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java index 69d489bf00d..afc526e81c7 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,15 @@ package jdk.test.lib.jittester; +import java.util.List; + import jdk.test.lib.jittester.utils.OptionResolver; import jdk.test.lib.jittester.utils.OptionResolver.Option; +import jdk.test.lib.jittester.utils.PseudoRandom; public class ProductionParams { + public static Option> mainClassNames = null; public static Option productionLimit = null; public static Option productionLimitSeconds = null; public static Option dataMemberLimit = null; @@ -72,6 +76,7 @@ public class ProductionParams { // workaraound: to reduce chance throwing ArrayIndexOutOfBoundsException public static Option chanceExpressionIndex = null; public static Option testbaseDir = null; + public static Option tempDir = null; public static Option numberOfTests = null; public static Option seed = null; public static Option specificSeed = null; @@ -81,6 +86,7 @@ public class ProductionParams { public static Option generatorsFactories = null; public static void register(OptionResolver optionResolver) { + mainClassNames = optionResolver.addRepeatingOption('k', "main-class", "", "Main class name"); productionLimit = optionResolver.addIntegerOption('l', "production-limit", 100, "Limit on steps in the production of an expression"); productionLimitSeconds = optionResolver.addIntegerOption("production-limit-seconds", 600, "Limit the time a test generation may take"); dataMemberLimit = optionResolver.addIntegerOption('v', "data-member-limit", 10, "Upper limit on data members"); @@ -124,6 +130,7 @@ public static void register(OptionResolver optionResolver) { enableFinalizers = optionResolver.addBooleanOption("enable-finalizers", "Enable finalizers (for stress testing)"); chanceExpressionIndex = optionResolver.addIntegerOption("chance-expression-index", 0, "A non negative decimal integer used to restrict chane of generating expression in array index while creating or accessing by index"); testbaseDir = optionResolver.addStringOption("testbase-dir", ".", "Testbase dir"); + tempDir = optionResolver.addStringOption("temp-dir", ".", "Temp dir path"); numberOfTests = optionResolver.addIntegerOption('n', "number-of-tests", 0, "Number of test classes to generate"); seed = optionResolver.addStringOption("seed", "", "Random seed"); specificSeed = optionResolver.addLongOption('z', "specificSeed", 0L, "A seed to be set for specific test generation(regular seed still needed for initialization)"); @@ -132,4 +139,18 @@ public static void register(OptionResolver optionResolver) { generators = optionResolver.addStringOption("generators", "", "Comma-separated list of generator names"); generatorsFactories = optionResolver.addStringOption("generatorsFactories", "", "Comma-separated list of generators factories class names"); } + + /** + * Initializes from the given command-line args + * + * @param args command-line arguments to use for initialization + */ + public static void initializeFromCmdline(String[] args) { + OptionResolver parser = new OptionResolver(); + Option propertyFileOpt = parser.addStringOption('p', "property-file", + "conf/default.properties", "File to read properties from"); + ProductionParams.register(parser); + parser.parse(args, propertyFileOpt); + PseudoRandom.reset(ProductionParams.seed.value()); + } } diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java index 5d8ac107d6a..3eee8e5a021 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java @@ -30,13 +30,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import jdk.test.lib.jittester.types.TypeKlass; -import jdk.test.lib.jittester.utils.PseudoRandom; -public abstract class TestsGenerator implements BiConsumer { +public abstract class TestsGenerator implements Consumer { private static final int DEFAULT_JTREG_TIMEOUT = 120; protected static final String JAVA_BIN = getJavaPath(); protected static final String JAVAC = Paths.get(JAVA_BIN, "javac").toString(); @@ -121,9 +120,9 @@ protected static void ensureExisting(Path path) { } } - protected String getJtregHeader(String mainClassName) { + protected String getJtregHeader(String mainClassName, long seed) { String synopsis = "seed = '" + ProductionParams.seed.value() + "'" - + ", specificSeed = '" + PseudoRandom.getCurrentSeed() + "'"; + + ", specificSeed = '" + seed + "'"; StringBuilder header = new StringBuilder(); header.append("/*\n * @test\n * @summary ") .append(synopsis) diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/utils/OptionResolver.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/utils/OptionResolver.java index 09f7f20695c..87207628df3 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/utils/OptionResolver.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/utils/OptionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -156,6 +156,12 @@ public Option addBooleanOption(String name, String description) { return addBooleanOption(null, name, false, description); } + public Option> addRepeatingOption(Character key, String name, String defaultValue, String description) { + final Option> option = new RepeatingOption(key, name, defaultValue, description); + register(option); + return option; + } + private void register(Option option) { if (options.put("--" + option.longName, option) != null) { throw new RuntimeException("Option is already registered for key " + option.longName); @@ -264,6 +270,20 @@ public Boolean parseFromString(String arg) { } } + private class RepeatingOption extends Option> { + List accumulated = new ArrayList(); + + RepeatingOption(Character s, String l, String v, String d) { + super(s, l, List.of(v), d); + } + + @Override + public List parseFromString(String arg) { + accumulated.add(arg); + return accumulated; + } + } + public Collection> getRegisteredOptions() { return Collections.unmodifiableSet(new LinkedHashSet<>(options.values())); } diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowTest/ShrinkGrowTest.java b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowTest/ShrinkGrowTest.java index f8a61c82d61..fffb10bbb3a 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowTest/ShrinkGrowTest.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/shrink_grow/ShrinkGrowTest/ShrinkGrowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ * @library /vmTestbase /test/lib * @run main/othervm * -XX:MetaspaceSize=10m - * -XX:MaxMetaspaceSize=20m + * -XX:MaxMetaspaceSize=10m * -Xlog:gc*:gc.log * metaspace.shrink_grow.ShrinkGrowTest.ShrinkGrowTest */ @@ -52,7 +52,7 @@ /** * This is the main test in the metaspace shrink/grow series. * - * It tries to allocate all available metespace (loads new classes and keeps + * It tries to allocate all available metaspace (loads new classes and keeps * them in map), then checks that loading new classes causes OOM. * After that it does cleanup loaded classes and then expect the new classes * could be loaded again. @@ -87,7 +87,7 @@ public static void main(String[] args) { * @param classesToLoad - the limit of classes to load expecting OOM */ public ShrinkGrowTest(String name, int classesToLoad) { - whoAmI = name; + whoAmI = "%" + name + "%"; maxClassesToLoad = classesToLoad; } @@ -98,15 +98,15 @@ public ShrinkGrowTest(String name, int classesToLoad) { * @param message text to print out */ void log(String message) { - System.out.println("%" + whoAmI + "% " + message); + System.out.println(whoAmI + message); } void throwFault(String message) { - throw new TestFault("%" + whoAmI + "% " + message); + throw new TestFault(whoAmI + message); } void throwFault(String message, Throwable t) { - throw new TestFault("%" + whoAmI + "% " + message, t); + throw new TestFault(whoAmI + message, t); } /** @@ -116,12 +116,12 @@ void throwFault(String message, Throwable t) { public void run() { if (System.getProperty("requiresCompressedClassSpace") != null && !isCompressedClassSpaceAvailable()) { - System.out.println("Not applicalbe, Compressed Class Space is required"); + System.out.println("Not applicable, Compressed Class Space is required"); return; } try { - log("Bootstrapping string concatenation for " + whoAmI ); + log("Bootstrapping string concatenation"); go(); // The quest completed! Yahoo! setErrorMessage(null); @@ -150,7 +150,17 @@ private void go() { throwFault("We haven't cleaned metaspace yet!"); } catch (OutOfMemoryError error) { if (!isMetaspaceError(error)) { - throwFault("Hmm, we ran out metaspace. Metaspace error is still excpected here " + error, error); + throwFault("Hmm, we ran out metaspace. Metaspace error is still expected here " + error, error); + } + } catch(BootstrapMethodError bsme) { + Throwable cause = bsme.getCause(); + if (cause instanceof OutOfMemoryError) { + OutOfMemoryError error = (OutOfMemoryError)cause; + if (!isMetaspaceError(error)) { + throwFault("Hmm, we got BootstrapMethodError. Metaspace error is still expected as the cause " + error, bsme); + } + } else { + throwFault("We should be out of metaspace but got " + cause, bsme); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java index 29d69b3174c..f7607b22e08 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/threadStartRequests/thrstartreq002.java @@ -127,6 +127,7 @@ private int runThis (String argv[], PrintStream out) { log2("debuggee launched"); } catch ( Exception e ) { log3("ERROR: Exception : " + e); + e.printStackTrace(System.out); log2(" test cancelled"); return FAILED; } @@ -170,6 +171,7 @@ private int runThis (String argv[], PrintStream out) { vm.exit(PASS_BASE); } catch ( Exception e ) { log3("ERROR: Exception : " + e); + e.printStackTrace(System.out); } break; @@ -183,6 +185,7 @@ private int runThis (String argv[], PrintStream out) { } } catch ( Exception e ) { log3("ERROR: Exception : " + e); + e.printStackTrace(System.out); } break; } @@ -211,9 +214,11 @@ private int runTest() { return 1; } catch ( VMDisconnectedException e ) { log3("ERROR: VMDisconnectedException : " + e); + e.printStackTrace(System.out); return 2; } catch ( Exception e ) { log3("ERROR: Exception : " + e); + e.printStackTrace(System.out); return 1; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldAccessWatch/clrfldw001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldAccessWatch/clrfldw001.java index 5724f0ea9f4..ffdc26b7cb1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldAccessWatch/clrfldw001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldAccessWatch/clrfldw001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ package nsk.jvmti.ClearFieldAccessWatch; +import jdk.test.lib.thread.TestThreadFactory; + import java.io.PrintStream; public class clrfldw001 { @@ -58,7 +60,7 @@ public static void main(String[] args) { public static int run(String argv[], PrintStream ref) { clrfldw001 t = new clrfldw001(); clrfldw001a t_a = new clrfldw001a(); - clrfldw001b t_b = new clrfldw001b(); + Thread t_b = TestThreadFactory.newThread(new clrfldw001b()); for (int i = 0; i < 5; i++) { setWatch(i); } @@ -91,7 +93,7 @@ class clrfldw001a { int fld = 2; } -class clrfldw001b extends Thread { +class clrfldw001b implements Runnable { float fld4 = 6.0f; public void run() { clrfldw001.clearWatch(4); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldModificationWatch/clrfmodw001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldModificationWatch/clrfmodw001.java index 9861f755f8f..7e1163d9102 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldModificationWatch/clrfmodw001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ClearFieldModificationWatch/clrfmodw001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ package nsk.jvmti.ClearFieldModificationWatch; +import jdk.test.lib.thread.TestThreadFactory; + import java.io.PrintStream; public class clrfmodw001 { @@ -58,7 +60,7 @@ public static void main(String[] args) { public static int run(String argv[], PrintStream ref) { clrfmodw001 t = new clrfmodw001(); clrfmodw001a t_a = new clrfmodw001a(); - clrfmodw001b t_b = new clrfmodw001b(); + Thread t_b = TestThreadFactory.newThread(new clrfmodw001b()); for (int i = 0; i < 5; i++) { setWatch(i); } @@ -91,7 +93,7 @@ class clrfmodw001a { int fld = 2; } -class clrfmodw001b extends Thread { +class clrfmodw001b implements Runnable { float fld4; public void run() { clrfmodw001.clearWatch(4); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001.java index 03951bf9769..fd64c4d3323 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ package nsk.jvmti.SetFieldAccessWatch; +import jdk.test.lib.thread.TestThreadFactory; + import java.io.PrintStream; public class setfldw001 { @@ -62,7 +64,7 @@ public static void main(String[] args) { public static int run(String argv[], PrintStream ref) { setfldw001 t = new setfldw001(); setfldw001a t_a = new setfldw001a(); - setfldw001b t_b = new setfldw001b(); + Thread t_b = TestThreadFactory.newThread(new setfldw001b()); t_b.start(); synchronized (lock) { fld = fld1 + 1; @@ -111,7 +113,7 @@ class setfldw001a { int fld = 2; } -class setfldw001b extends Thread { +class setfldw001b implements Runnable { float fld4 = 6.0f; public void run() { synchronized (setfldw001.lock) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldModificationWatch/setfmodw001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldModificationWatch/setfmodw001.java index a545a41f2fd..b79120e404c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldModificationWatch/setfmodw001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SetFieldModificationWatch/setfmodw001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ package nsk.jvmti.SetFieldModificationWatch; +import jdk.test.lib.thread.TestThreadFactory; + import java.io.PrintStream; public class setfmodw001 { @@ -62,7 +64,7 @@ public static void main(String[] args) { public static int run(String argv[], PrintStream ref) { setfmodw001 t = new setfmodw001(); setfmodw001a t_a = new setfmodw001a(); - setfmodw001b t_b = new setfmodw001b(); + Thread t_b = TestThreadFactory.newThread(new setfmodw001b()); t_b.start(); synchronized (lock) { fld1 = fld1 + 1; @@ -111,7 +113,7 @@ class setfmodw001a { int fld = 2; } -class setfmodw001b extends Thread { +class setfmodw001b implements Runnable { float fld4; public void run() { synchronized (setfmodw001.lock) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java index 871b6d26aff..ea15f3d0d35 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ThreadController.java @@ -665,7 +665,6 @@ public SleepingThread(ThreadController controller, String name, Log log, Threads // jdk.internal.event.ThreadSleepEvent not accessible expectedMethods.add("jdk.internal.event.ThreadSleepEvent."); expectedMethods.add("jdk.internal.event.ThreadSleepEvent.isEnabled"); - expectedMethods.add("jdk.internal.event.ThreadSleepEvent.isTurnedOn"); expectedMethods.add(SleepingThread.class.getName() + ".run"); switch (controller.invocationType) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java index f23c16cd047..ed2a1a60c50 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/thread/SleepingThread.java @@ -42,7 +42,6 @@ public class SleepingThread extends RecursiveMonitoringThread { "java.lang.Thread.afterSleep", "java.util.concurrent.TimeUnit.toNanos", "jdk.internal.event.ThreadSleepEvent.", - "jdk.internal.event.ThreadSleepEvent.isTurnedOn", "jdk.internal.event.ThreadSleepEvent.isEnabled", "nsk.monitoring.share.thread.SleepingThread.runInside" }; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java index 632cebae8f8..03d2066cf32 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001.java @@ -151,7 +151,6 @@ private static boolean fillTrace() { "java.util.concurrent.TimeUnit.toNanos", "jdk.internal.event.ThreadSleepEvent.", "jdk.internal.event.ThreadSleepEvent.", - "jdk.internal.event.ThreadSleepEvent.isTurnedOn", "jdk.internal.event.ThreadSleepEvent.isEnabled" }; diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 67eceaa5a3e..6198d332142 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -101,6 +101,7 @@ requires.properties= \ vm.jvmti \ vm.cpu.features \ docker.support \ + systemd.support \ release.implementor \ jdk.containerized \ jdk.foreign.linker diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 809860a3b1f..92c594bf9d3 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -272,6 +272,7 @@ jdk_text = \ jdk_management = \ java/lang/management \ + jdk/management \ com/sun/management \ sun/management \ jdk/internal/agent @@ -297,6 +298,7 @@ jdk_launcher = \ jdk_loom = \ com/sun/management/HotSpotDiagnosticMXBean \ com/sun/management/ThreadMXBean \ + jdk/management/VirtualThreadSchedulerMXBean \ java/lang/Thread \ java/lang/ThreadGroup \ java/lang/management/ThreadMXBean \ diff --git a/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java index a07620dbd38..f2ceba47d0d 100644 --- a/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java +++ b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java @@ -46,40 +46,47 @@ public class CheckboxCheckerScalingTest { private static Frame frame; private static Checkbox checkbox; - private static BufferedImage imageAfterChecked; - private static volatile boolean checkmarkFound = false; + private static volatile Point point; + private static boolean checkmarkFound = false; + private static final int TOLERANCE = 5; + private static final int COLOR_CHECK_THRESHOLD = 8; + private static int colorCounter = 0; public static void main(String[] args) throws Exception { System.setProperty("sun.java2d.uiScale", "2"); Robot robot = new Robot(); + try { EventQueue.invokeAndWait(() -> { - frame = new Frame("ComboBox checker scaling test"); + frame = new Frame("CheckBox checker scaling test"); checkbox = new Checkbox("one"); checkbox.setState(true); frame.add(checkbox); + frame.setLocationRelativeTo(null); frame.pack(); frame.setVisible(true); }); robot.waitForIdle(); robot.delay(100); - EventQueue.invokeAndWait(() -> { - Point point = checkbox.getLocationOnScreen(); - Rectangle rect = new Rectangle(point.x + 5, point.y + 7, 8, 8); - imageAfterChecked = robot.createScreenCapture(rect); - - check: { - for (int i = 0; i < imageAfterChecked.getHeight(); i++) { - for (int j = 0; j < imageAfterChecked.getWidth(); j++) { - if (Color.black.getRGB() == imageAfterChecked.getRGB(i, j)) { + EventQueue.invokeAndWait(() -> point = checkbox.getLocationOnScreen()); + Rectangle rect = new Rectangle(point.x + 5, point.y + 7, 8, 8); + BufferedImage imageAfterChecked = robot.createScreenCapture(rect); + check: + { + for (int i = 0; i < imageAfterChecked.getHeight(); i++) { + for (int j = 0; j < imageAfterChecked.getWidth(); j++) { + Color pixelColor = new Color(imageAfterChecked.getRGB(i, j)); + if (compareColor(pixelColor)) { + if (++colorCounter >= COLOR_CHECK_THRESHOLD) { checkmarkFound = true; break check; } } + } } - }); + } if (!checkmarkFound) { try { @@ -99,4 +106,10 @@ public static void main(String[] args) throws Exception { }); } } + + private static boolean compareColor(Color c) { + return Math.abs(Color.black.getRed() - c.getRed()) < TOLERANCE && + Math.abs(Color.black.getGreen() - c.getGreen()) < TOLERANCE && + Math.abs(Color.black.getBlue() - c.getBlue()) < TOLERANCE; + } } diff --git a/test/jdk/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java b/test/jdk/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java index cb20a2f2732..91d277a2284 100644 --- a/test/jdk/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java +++ b/test/jdk/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ @summary Tests that windows are removed from owner's child windows list @modules java.desktop/java.awt:open @author art: area=awt.toplevel - @run main/othervm -mx128m OwnedWindowsLeak + @run main/othervm -Xmx128m OwnedWindowsLeak */ import java.awt.Frame; diff --git a/test/jdk/java/beans/Introspector/8159696/UnloadClassBeanInfo.java b/test/jdk/java/beans/Introspector/8159696/UnloadClassBeanInfo.java index 8c77b3565a8..0d9775d50d6 100644 --- a/test/jdk/java/beans/Introspector/8159696/UnloadClassBeanInfo.java +++ b/test/jdk/java/beans/Introspector/8159696/UnloadClassBeanInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, 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 @@ -38,7 +38,7 @@ * @bug 8159696 * @library /javax/swing/regtesthelpers * @compile ./stub/Stub.java - * @run main/othervm -mx32M UnloadClassBeanInfo + * @run main/othervm -Xmx32M UnloadClassBeanInfo */ public class UnloadClassBeanInfo { diff --git a/test/jdk/java/beans/Introspector/Test5102804.java b/test/jdk/java/beans/Introspector/Test5102804.java index d5b38ea10d0..0563b1d306d 100644 --- a/test/jdk/java/beans/Introspector/Test5102804.java +++ b/test/jdk/java/beans/Introspector/Test5102804.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, 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,8 +25,7 @@ * @test * @bug 5102804 * @summary Tests memory leak - * @author Sergey Malenkov - * @run main/othervm -ms16m -mx16m Test5102804 + * @run main/othervm -Xms16m -Xmx16m Test5102804 */ import java.beans.BeanInfo; diff --git a/test/jdk/java/beans/Introspector/Test8027905.java b/test/jdk/java/beans/Introspector/Test8027905.java index 60318f34555..8ebf1c59574 100644 --- a/test/jdk/java/beans/Introspector/Test8027905.java +++ b/test/jdk/java/beans/Introspector/Test8027905.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,7 @@ * @test * @bug 8027905 * @summary Tests that GC does not affect a property type - * @author Sergey Malenkov - * @run main/othervm -mx16m Test8027905 + * @run main/othervm -Xmx16m Test8027905 */ public class Test8027905 { diff --git a/test/jdk/java/beans/XMLEncoder/Test4646747.java b/test/jdk/java/beans/XMLEncoder/Test4646747.java index 61f7c41c882..467a0153228 100644 --- a/test/jdk/java/beans/XMLEncoder/Test4646747.java +++ b/test/jdk/java/beans/XMLEncoder/Test4646747.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, 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,8 +25,7 @@ * @test * @bug 4646747 * @summary Tests that persistence delegate is correct after memory stress - * @author Mark Davidson - * @run main/othervm -ms16m -mx16m Test4646747 + * @run main/othervm -Xms16m -Xmx16m Test4646747 */ import java.beans.DefaultPersistenceDelegate; diff --git a/test/jdk/java/foreign/TestMappedHandshake.java b/test/jdk/java/foreign/TestMappedHandshake.java new file mode 100644 index 00000000000..46fb4fb45fb --- /dev/null +++ b/test/jdk/java/foreign/TestMappedHandshake.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2024, 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 + * @requires vm.flavor != "zero" + * @modules java.base/jdk.internal.vm.annotation java.base/jdk.internal.misc + * @key randomness + * @run testng/othervm TestMappedHandshake + * @run testng/othervm -Xint TestMappedHandshake + * @run testng/othervm -XX:TieredStopAtLevel=1 TestMappedHandshake + * @run testng/othervm -XX:-TieredCompilation TestMappedHandshake + */ + +import java.io.File; +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +public class TestMappedHandshake { + + static final int SEGMENT_SIZE = 1_000_000; + static final int ACCESS_START_DELAY_MILLIS = 100; + static final int POST_ACCESS_DELAY_MILLIS = 1; + static final int TIMED_RUN_TIME_SECONDS = 10; + static final int MAX_EXECUTOR_WAIT_SECONDS = 20; + + static final int NUM_ACCESSORS = 5; + + static final Path tempPath; + + static { + try { + File file = File.createTempFile("buffer", "txt"); + file.deleteOnExit(); + tempPath = file.toPath(); + Files.write(file.toPath(), new byte[SEGMENT_SIZE], StandardOpenOption.WRITE); + + } catch (IOException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + @Test + public void testHandshake() throws InterruptedException, IOException { + try (FileChannel fileChannel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE) ; + Arena arena = Arena.ofShared()) { + MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, SEGMENT_SIZE, arena); + ExecutorService accessExecutor = Executors.newFixedThreadPool(NUM_ACCESSORS + 1); + // start handshaker + accessExecutor.execute(new Handshaker()); + Thread.sleep(ACCESS_START_DELAY_MILLIS); + // start accessors + for (int i = 0 ; i < NUM_ACCESSORS ; i++) { + accessExecutor.execute(new MappedSegmentAccessor(segment)); + } + + accessExecutor.shutdown(); + assertTrue(accessExecutor.awaitTermination(MAX_EXECUTOR_WAIT_SECONDS, TimeUnit.SECONDS)); + } + } + + static abstract class TimedAction implements Runnable { + @Override + public void run() { + long start = System.currentTimeMillis(); + while (true) { + try { + doAction(); + } catch (Throwable ex) { + // ignore + } finally { + long elapsed = System.currentTimeMillis() - start; + if (elapsed > TIMED_RUN_TIME_SECONDS * 1000) { + break; + } + } + } + } + + abstract void doAction() throws Throwable; + } + + static class MappedSegmentAccessor extends TimedAction { + + final MemorySegment segment; + + MappedSegmentAccessor(MemorySegment segment) { + this.segment = segment; + } + + @Override + void doAction() throws Throwable { + segment.load(); + Thread.sleep(POST_ACCESS_DELAY_MILLIS); + segment.isLoaded(); + Thread.sleep(POST_ACCESS_DELAY_MILLIS); + segment.unload(); + Thread.sleep(POST_ACCESS_DELAY_MILLIS); + segment.force(); + } + } + + static class Handshaker extends TimedAction { + + @Override + public void doAction() { + Arena.ofShared().close(); + } + } +} diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java index 88636bf5420..9a4500b2f5a 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -30,7 +30,6 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; import java.util.ArrayList; @@ -76,6 +75,94 @@ public void testByteCopy(SegmentKind kind1, SegmentKind kind2) { } } + @Test(dataProvider = "conjunctSegments") + public void testCopy5ArgInvariants(MemorySegment src, MemorySegment dst) { + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, 0, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, -1, dst, 0, src.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, -1, src.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 1, dst, 0, src.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, 1, src.byteSize())); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy7ArgRight(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 0, dst, 1, CopyOp.of7Arg()); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy5ArgRight(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 0, dst, 1, CopyOp.of5Arg()); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy7ArgLeft(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 1, dst, 0, CopyOp.of7Arg()); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy5ArgLeft(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 1, dst, 0, CopyOp.of5Arg()); + } + + void testConjunctCopy(MemorySegment src, long srcOffset, MemorySegment dst, long dstOffset, CopyOp op) { + if (src.byteSize() < 4 || src.address() != dst.address()) { + // Only test larger segments where the skew is zero + return; + } + + try (var arena = Arena.ofConfined()) { + // Create a disjoint segment for expected behavior + MemorySegment disjoint = arena.allocate(dst.byteSize()); + disjoint.copyFrom(src); + op.copy(src, srcOffset, disjoint, dstOffset, 3); + byte[] expected = disjoint.toArray(JAVA_BYTE); + + // Do a conjoint copy + op.copy(src, srcOffset, dst, dstOffset, 3); + byte[] actual = dst.toArray(JAVA_BYTE); + + assertEquals(actual, expected); + } + } + + @FunctionalInterface + interface CopyOp { + void copy(MemorySegment src, long srcOffset, MemorySegment dst, long dstOffset, long bytes); + + static CopyOp of5Arg() { + return MemorySegment::copy; + } + + static CopyOp of7Arg() { + return (MemorySegment src, long srcOffset, MemorySegment dst, long dstOffset, long bytes) -> + MemorySegment.copy(src, JAVA_BYTE, srcOffset, dst, JAVA_BYTE, dstOffset, bytes); + } + + } + + @Test(dataProvider = "segmentKinds") + public void testByteCopySizes(SegmentKind kind1, SegmentKind kind2) { + + record Offsets(int src, int dst){} + + for (Offsets offsets : List.of(new Offsets(3, 7), new Offsets(7, 3))) { + for (int size = 0; size < 513; size++) { + MemorySegment src = kind1.makeSegment(size + offsets.src()); + MemorySegment dst = kind2.makeSegment(size + offsets.dst()); + //prepare source slice + for (int i = 0; i < size; i++) { + src.set(JAVA_BYTE, i + offsets.src(), (byte) i); + } + //perform copy + MemorySegment.copy(src, offsets.src(), dst, offsets.dst(), size); + //check that copy actually worked + for (int i = 0; i < size; i++) { + assertEquals(dst.get(JAVA_BYTE, i + offsets.dst()), (byte) i); + } + } + } + } + @Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "segmentKinds") public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) { MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); @@ -277,6 +364,28 @@ static Object[][] segmentKinds() { return cases.toArray(Object[][]::new); } + @DataProvider + static Object[][] conjunctSegments() { + List cases = new ArrayList<>(); + for (SegmentKind kind : SegmentKind.values()) { + // Different paths might be taken in the implementation depending on the + // size, type, and address of the underlying segments. + for (int len : new int[]{0, 1, 7, 512}) { + for (int offset : new int[]{-1, 0, 1}) { + MemorySegment segment = kind.makeSegment(len + 2); + MemorySegment src = segment.asSlice(1 + offset, len); + MemorySegment dst = segment.asSlice(1, len); + for (int i = 0; i < len; i++) { + src.set(JAVA_BYTE, i, (byte) i); + } + // src = 0, 1, ... , len-1 + cases.add(new Object[]{src, dst}); + } + } + } + return cases.toArray(Object[][]::new); + } + @DataProvider static Object[][] types() { return Arrays.stream(Type.values()) diff --git a/test/jdk/java/foreign/largestub/TestLargeStub.java b/test/jdk/java/foreign/largestub/TestLargeStub.java index eaf82648778..e4dcb325c8f 100644 --- a/test/jdk/java/foreign/largestub/TestLargeStub.java +++ b/test/jdk/java/foreign/largestub/TestLargeStub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,29 +25,39 @@ * @test * @library ../ * @modules java.base/jdk.internal.foreign - * @run testng/othervm --enable-native-access=ALL-UNNAMED TestLargeStub + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestLargeStub */ -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.Linker; import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; import java.util.stream.Stream; +import static org.junit.jupiter.params.provider.Arguments.arguments; + public class TestLargeStub extends NativeTestHelper { + private static final int DOWNCALL_AVAILABLE_SLOTS = 248; + private static final int UPCALL_AVAILABLE_SLOTS = 250; + MemoryLayout STRUCT_LL = MemoryLayout.structLayout( C_LONG_LONG, C_LONG_LONG ); // 16 byte struct triggers return buffer usage on SysV - @Test - public void testDowncall() { + @ParameterizedTest + @MethodSource("layouts") + public void testDowncall(ValueLayout layout, int numSlots) { // Link a handle with a large number of arguments, to try and overflow the code buffer Linker.nativeLinker().downcallHandle( FunctionDescriptor.of(STRUCT_LL, - Stream.generate(() -> C_DOUBLE).limit(124).toArray(MemoryLayout[]::new)), + Stream.generate(() -> layout).limit(DOWNCALL_AVAILABLE_SLOTS / numSlots).toArray(MemoryLayout[]::new)), Linker.Option.captureCallState("errno")); } @@ -62,11 +72,21 @@ public void testDowncallAllowHeap() { Linker.Option.critical(true)); } - @Test - public void testUpcall() { + @ParameterizedTest + @MethodSource("layouts") + public void testUpcall(ValueLayout layout, int numSlots) { // Link a handle with a large number of arguments, to try and overflow the code buffer Linker.nativeLinker().downcallHandle( FunctionDescriptor.of(STRUCT_LL, - Stream.generate(() -> C_DOUBLE).limit(125).toArray(MemoryLayout[]::new))); + Stream.generate(() -> layout).limit(UPCALL_AVAILABLE_SLOTS / numSlots).toArray(MemoryLayout[]::new))); + } + + private static Stream layouts() { + return Stream.of( + arguments(C_INT, 1), + arguments(C_LONG_LONG, 2), + arguments(C_FLOAT, 1), + arguments(C_DOUBLE, 2) + ); } } diff --git a/test/jdk/java/io/File/GetCanonicalPath.java b/test/jdk/java/io/File/GetCanonicalPath.java index e54227e44b4..d69e90fbbfc 100644 --- a/test/jdk/java/io/File/GetCanonicalPath.java +++ b/test/jdk/java/io/File/GetCanonicalPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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,17 +22,21 @@ */ /* @test - * @bug 4899022 + * @bug 4899022 8003887 * @summary Look for erroneous representation of drive letter * @run junit GetCanonicalPath */ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -122,4 +126,88 @@ void driveLetter() throws IOException { String path = new File("c:/").getCanonicalPath(); assertFalse(path.length() > 3, "Drive letter incorrectly represented"); } + + // Create a File with the given pathname and return the File as a Path + private static Path createFile(String pathname) throws IOException { + File file = new File(pathname); + file.deleteOnExit(); + return file.toPath(); + } + + private static boolean supportsLinks = true; + private static String linkMessage; + + private static Path link; + private static Path sublink; + private static Path subsub; + + @BeforeAll + static void createSymlinks() throws IOException { + final String DIR = "dir"; + final String SUBDIR = "subdir"; + final String TARGET = "target.txt"; + final String LINK = "link"; + final String SUBLINK = "sublink"; + final String FILE = "file.txt"; + + // Create directories dir/subdir + Path dir = createFile(DIR); + Path subdir = createFile(dir.resolve(SUBDIR).toString()); + Files.createDirectories(subdir); + + // Create file dir/subdir/target.txt + Path target = createFile(subdir.resolve(TARGET).toString()); + Files.createFile(target); + + // Create symbolic link link -> dir + link = createFile(Path.of(LINK).toString()); + try { + Files.createSymbolicLink(link, dir); + } catch (UnsupportedOperationException | IOException x) { + if (OS.WINDOWS.isCurrentOs()) { + supportsLinks = false; + linkMessage = "\"" + x.getMessage() + "\""; + return; + } else { + throw x; + } + } + + sublink = createFile(Path.of(DIR, SUBDIR, SUBLINK).toString()); + Path file = createFile(Path.of(DIR, SUBDIR, FILE).toString()); + Files.createFile(file); + + // Create symbolic link dir/subdir/sublink -> file.txt + Files.createSymbolicLink(sublink, Path.of(FILE)); + sublink.toFile().deleteOnExit(); + + subsub = createFile(Path.of(LINK, SUBDIR, SUBLINK).toString()); + } + + @Test + void linkToDir() throws IOException { + Assumptions.assumeTrue(supportsLinks, linkMessage); + + // Check link evaluates to dir + assertEquals(link.toRealPath().toString(), + link.toFile().getCanonicalPath()); + } + + @Test + void linkToFile() throws IOException { + Assumptions.assumeTrue(supportsLinks, linkMessage); + + // Check sublink evaluates to file.txt + assertEquals(sublink.toRealPath().toString(), + sublink.toFile().getCanonicalPath()); + } + + @Test + void linkToFileInSubdir() throws IOException { + Assumptions.assumeTrue(supportsLinks, linkMessage); + + // Check link/subdir/sublink evaluates to dir/subdir/file.txt + assertEquals(subsub.toRealPath().toString(), + subsub.toFile().getCanonicalPath()); + } } diff --git a/test/jdk/java/lang/String/CountNonZeroAscii.java b/test/jdk/java/lang/String/CountNonZeroAscii.java new file mode 100644 index 00000000000..d4b8a4fb1eb --- /dev/null +++ b/test/jdk/java/lang/String/CountNonZeroAscii.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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 jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/* + * @test + * @modules java.base/jdk.internal.access + * @summary test latin1 String countNonZeroAscii + * @run main/othervm -XX:+CompactStrings CountNonZeroAscii + * @run main/othervm -XX:-CompactStrings CountNonZeroAscii + */ +public class CountNonZeroAscii { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + public static void main(String [] args) { + byte[] bytes = new byte[1000]; + + Arrays.fill(bytes, (byte) 'A'); + String s = new String(bytes, StandardCharsets.ISO_8859_1); + assertEquals(bytes.length, JLA.countNonZeroAscii(s)); + + for (int i = 0; i < bytes.length; i++) { + for (int j = Byte.MIN_VALUE; j <= 0; j++) { + bytes[i] = (byte) j; + s = new String(bytes, StandardCharsets.ISO_8859_1); + assertEquals(i, JLA.countNonZeroAscii(s)); + } + bytes[i] = (byte) 'A'; + } + } + + static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new AssertionError("Expected " + expected + " but got " + actual); + } + } +} diff --git a/test/jdk/java/lang/Thread/virtual/BigStackChunk.java b/test/jdk/java/lang/Thread/virtual/BigStackChunk.java new file mode 100644 index 00000000000..1e76856d3c0 --- /dev/null +++ b/test/jdk/java/lang/Thread/virtual/BigStackChunk.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024, 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 id=default + * @bug 8335362 + * @summary Test virtual thread usage with big stackChunks + * @requires vm.continuations + * @run junit/othervm BigStackChunk + */ + +import java.util.concurrent.locks.ReentrantLock; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class BigStackChunk { + + void recurse(int cnt, ReentrantLock rlock) { + int i1 = cnt; + int i2 = i1 + 1; + int i3 = i2 + 1; + int i4 = i3 + 1; + int i5 = i4 + 1; + int i6 = i5 + 1; + int i7 = i6 + 1; + long ll = 2 * (long)i1; + float ff = ll + 1.2f; + double dd = ff + 1.3D; + + if (cnt > 0) { + recurse(cnt - 1, rlock); + } else { + rlock.lock(); + rlock.unlock(); + } + } + + @Test + void bigStackChunkTest() throws Exception { + int VTHREAD_CNT = Runtime.getRuntime().availableProcessors(); + ReentrantLock rlock = new ReentrantLock(); + Thread[] vthreads = new Thread[VTHREAD_CNT]; + + rlock.lock(); + for (int i = 0; i < VTHREAD_CNT; i++) { + vthreads[i] = Thread.ofVirtual().start(() -> { + // Set up things so that half of the carriers will commit lots of + // pages in the stack while running the mounted vthread and half + // will just commit very few ones. + if (Math.random() < 0.5) { + recurse(300, rlock); + } else { + recurse(1, rlock); + } + }); + } + await(vthreads[0], Thread.State.WAITING); + // Now we expect that some vthread that recursed a lot is mounted on + // a carrier that previously run a vthread that didn't recurse at all. + rlock.unlock(); + + for (int i = 0; i < VTHREAD_CNT; i++) { + vthreads[i].join(); + } + } + + private void await(Thread thread, Thread.State expectedState) throws InterruptedException { + Thread.State state = thread.getState(); + while (state != expectedState) { + assertTrue(state != Thread.State.TERMINATED, "Thread has terminated"); + Thread.sleep(10); + state = thread.getState(); + } + } +} \ No newline at end of file diff --git a/test/jdk/java/lang/Thread/virtual/JfrEvents.java b/test/jdk/java/lang/Thread/virtual/JfrEvents.java index 539ac2104ed..bc952331f64 100644 --- a/test/jdk/java/lang/Thread/virtual/JfrEvents.java +++ b/test/jdk/java/lang/Thread/virtual/JfrEvents.java @@ -25,7 +25,7 @@ * @test * @summary Basic test for JFR jdk.VirtualThreadXXX events * @requires vm.continuations - * @modules jdk.jfr java.base/java.lang:+open + * @modules jdk.jfr java.base/java.lang:+open jdk.management * @library /test/lib * @run junit/othervm --enable-native-access=ALL-UNNAMED JfrEvents */ @@ -50,7 +50,7 @@ import jdk.jfr.consumer.RecordingFile; import jdk.test.lib.thread.VThreadPinner; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management import jdk.test.lib.thread.VThreadScheduler; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; diff --git a/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java b/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java index d1f2bf0c1bf..c2389ab7ddd 100644 --- a/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorEnterExit.java @@ -24,7 +24,7 @@ /* * @test id=default * @summary Test virtual thread with monitor enter/exit - * @modules java.base/java.lang:+open + * @modules java.base/java.lang:+open jdk.management * @library /test/lib * @run junit/othervm --enable-native-access=ALL-UNNAMED MonitorEnterExit */ @@ -43,7 +43,7 @@ import java.util.stream.Stream; import jdk.test.lib.thread.VThreadPinner; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management import jdk.test.lib.thread.VThreadScheduler; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; diff --git a/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java index 5f730dbbf0a..81f1c1ea97f 100644 --- a/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java +++ b/test/jdk/java/lang/Thread/virtual/MonitorWaitNotify.java @@ -24,7 +24,7 @@ /* * @test id=default * @summary Test virtual threads using Object.wait/notifyAll - * @modules java.base/java.lang:+open + * @modules java.base/java.lang:+open jdk.management * @library /test/lib * @run junit/othervm --enable-native-access=ALL-UNNAMED MonitorWaitNotify */ @@ -46,8 +46,7 @@ import java.util.stream.Collectors; import jdk.test.lib.thread.VThreadScheduler; -import jdk.test.lib.thread.VThreadRunner; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management import jdk.test.lib.thread.VThreadPinner; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; diff --git a/test/jdk/java/lang/Thread/virtual/ThreadAPI.java b/test/jdk/java/lang/Thread/virtual/ThreadAPI.java index 3bb5c75a1b5..cda302f391f 100644 --- a/test/jdk/java/lang/Thread/virtual/ThreadAPI.java +++ b/test/jdk/java/lang/Thread/virtual/ThreadAPI.java @@ -25,7 +25,7 @@ * @test id=default * @bug 8284161 8286788 8321270 * @summary Test Thread API with virtual threads - * @modules java.base/java.lang:+open + * @modules java.base/java.lang:+open jdk.management * @library /test/lib * @run junit/othervm --enable-native-access=ALL-UNNAMED ThreadAPI */ @@ -33,7 +33,7 @@ /* * @test id=no-vmcontinuations * @requires vm.continuations - * @modules java.base/java.lang:+open + * @modules java.base/java.lang:+open jdk.management * @library /test/lib * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations * --enable-native-access=ALL-UNNAMED ThreadAPI @@ -62,7 +62,7 @@ import java.nio.channels.Selector; import jdk.test.lib.thread.VThreadPinner; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management import jdk.test.lib.thread.VThreadScheduler; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; diff --git a/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java b/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java index 0c5f1c3d6b4..2d822655428 100644 --- a/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java +++ b/test/jdk/java/lang/Thread/virtual/VirtualThreadPinnedEventThrows.java @@ -24,7 +24,7 @@ /** * @test * @summary Test parking when pinned and emitting the JFR VirtualThreadPinnedEvent throws - * @modules java.base/java.lang:+open java.base/jdk.internal.event + * @modules java.base/java.lang:+open java.base/jdk.internal.event jdk.management * @library /test/lib * @compile/module=java.base jdk/internal/event/VirtualThreadPinnedEvent.java * @run junit/othervm --enable-native-access=ALL-UNNAMED VirtualThreadPinnedEventThrows @@ -36,7 +36,7 @@ import java.util.concurrent.locks.LockSupport; import jdk.internal.event.VirtualThreadPinnedEvent; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management import jdk.test.lib.thread.VThreadPinner; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeAll; diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java index a5aea9ee398..5e15ea083e4 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenBlocking.java @@ -26,7 +26,7 @@ * @summary Stress test Thread.getStackTrace on virtual threads that are blocking or * blocked on monitorenter * @requires vm.debug != true - * @modules java.base/java.lang:+open + * @modules jdk.management * @library /test/lib * @run main/othervm GetStackTraceALotWhenBlocking 500000 */ @@ -34,7 +34,7 @@ /* * @test * @requires vm.debug == true & vm.continuations - * @modules java.base/java.lang:+open + * @modules jdk.management * @library /test/lib * @run main/othervm/timeout=300 GetStackTraceALotWhenBlocking 50000 */ @@ -42,7 +42,7 @@ import java.time.Instant; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management public class GetStackTraceALotWhenBlocking { diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java index d7e6c3a8de4..260446a1e3d 100644 --- a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java @@ -26,7 +26,7 @@ * @bug 8322818 * @summary Stress test Thread.getStackTrace on a virtual thread that is pinned * @requires vm.debug != true - * @modules java.base/java.lang:+open + * @modules jdk.management * @library /test/lib * @run main/othervm --enable-native-access=ALL-UNNAMED GetStackTraceALotWhenPinned 500000 */ @@ -34,7 +34,7 @@ /* * @test * @requires vm.debug == true - * @modules java.base/java.lang:+open + * @modules jdk.management * @library /test/lib * @run main/othervm/timeout=300 --enable-native-access=ALL-UNNAMED GetStackTraceALotWhenPinned 200000 */ @@ -42,7 +42,7 @@ import java.time.Instant; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management import jdk.test.lib.thread.VThreadPinner; public class GetStackTraceALotWhenPinned { diff --git a/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java b/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java index d4da6073337..91b31c41be3 100644 --- a/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java +++ b/test/jdk/java/lang/management/ThreadMXBean/VirtualThreadDeadlocks.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,7 @@ * @bug 8284161 8287103 * @summary Test ThredMXBean.findMonitorDeadlockedThreads with cycles of * platform and virtual threads in deadlock - * @modules java.base/java.lang:+open java.management + * @modules java.management jdk.management * @library /test/lib * @run main/othervm VirtualThreadDeadlocks PP * @run main/othervm VirtualThreadDeadlocks PV @@ -36,7 +36,7 @@ /** * @test id=no-vmcontinuations * @requires vm.continuations - * @modules java.base/java.lang:+open java.management + * @modules java.management jdk.management * @library /test/lib * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations VirtualThreadDeadlocks PP * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations VirtualThreadDeadlocks PV @@ -48,7 +48,7 @@ import java.util.Arrays; import java.util.concurrent.CyclicBarrier; import java.util.stream.Stream; -import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management public class VirtualThreadDeadlocks { private static final Object LOCK1 = new Object(); diff --git a/test/jdk/java/lang/ref/SoftReference/Pin.java b/test/jdk/java/lang/ref/SoftReference/Pin.java index 5416b0f575a..35aa4d9a512 100644 --- a/test/jdk/java/lang/ref/SoftReference/Pin.java +++ b/test/jdk/java/lang/ref/SoftReference/Pin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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,9 +24,7 @@ /* @test * @bug 4076287 * @summary Invoking get on a SoftReference shouldn't pin the referent - * @run main/othervm -ms16m -mx16m Pin - * @author Peter Jones - * @author Mark Reinhold + * @run main/othervm -Xms16m -Xmx16m Pin */ diff --git a/test/jdk/java/nio/Buffer/Chew.java b/test/jdk/java/nio/Buffer/Chew.java index b1afeabc472..30932be526a 100644 --- a/test/jdk/java/nio/Buffer/Chew.java +++ b/test/jdk/java/nio/Buffer/Chew.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, 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,7 @@ * @summary Ensure that direct memory can be unreserved * as the reserving thread sleeps * - * @run main/othervm -mx16M Chew + * @run main/othervm -Xmx16M Chew */ import java.nio.*; diff --git a/test/jdk/java/security/SecureRandom/ThreadSafe.java b/test/jdk/java/security/SecureRandom/ThreadSafe.java index 174f3253c5f..b0975678e96 100644 --- a/test/jdk/java/security/SecureRandom/ThreadSafe.java +++ b/test/jdk/java/security/SecureRandom/ThreadSafe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, 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 @@ -21,33 +21,46 @@ * questions. */ +import static jdk.test.lib.Utils.runAndCheckException; + +import java.lang.Override; import java.security.Provider; import java.security.SecureRandom; import java.security.SecureRandomSpi; +import java.util.List; import java.util.Map; /* * @test - * @bug 7004967 + * @library /test/lib + * @bug 7004967 8329754 * @summary SecureRandom should be more explicit about threading */ + public class ThreadSafe { public static void main(String[] args) throws Exception { Provider p = new P(); NoSync.test(SecureRandom.getInstance("S1", p), 5, 5); - try { - NoSync.test(SecureRandom.getInstance("S2", p), 5, 5); - throw new Exception("Failed"); - } catch (RuntimeException re) { - // Good - } + NoSync.test(SecureRandom.getInstance("AliasS1", p), 5, 5); + + runAndCheckException( + () -> NoSync.test(SecureRandom.getInstance("S2", p), 5, 5), + RuntimeException.class); + + runAndCheckException( + () -> NoSync.test(SecureRandom.getInstance("AliasS2", p), 5, 5), + RuntimeException.class); + NoSync.test(SecureRandom.getInstance("S3", p), 5, 5); - try { - NoSync.test(SecureRandom.getInstance("S4", p), 5, 5); - throw new Exception("Failed"); - } catch (RuntimeException re) { - // Good - } + NoSync.test(SecureRandom.getInstance("AliasS3", p), 5, 5); + + runAndCheckException( + () -> NoSync.test(SecureRandom.getInstance("S4", p), 5, 5), + RuntimeException.class); + + runAndCheckException( + () -> NoSync.test(SecureRandom.getInstance("AliasS4", p), 5, 5), + RuntimeException.class); } public static class P extends Provider { @@ -58,28 +71,36 @@ public P() { // Good. No attribute. put("SecureRandom.S1", S.class.getName()); + // Good. Alias of S1, should pass because S1 is not marked as ThreadSafe + put("Alg.alias.SecureRandom.AliasS1", "S1"); + // Bad. Boasting ThreadSafe but isn't put("SecureRandom.S2", S.class.getName()); put("SecureRandom.S2 ThreadSafe", "true"); + //Bad. Alias of S2, should fail because S2 is marked as ThreadSafe + put("alg.Alias.SecureRandom.AliasS2", "S2"); + // Good. No attribute. putService(new Service(this, "SecureRandom", "S3", - S.class.getName(), null, null)); + S.class.getName(), List.of("AliasS3"), null)); // Bad. Boasting ThreadSafe but isn't putService(new Service(this, "SecureRandom", "S4", - S.class.getName(), null, Map.of("ThreadSafe", "true"))); + S.class.getName(), List.of("AliasS4"), Map.of("ThreadSafe", "true"))); } } // This implementation is not itself thread safe. public static class S extends SecureRandomSpi { - @java.lang.Override + + @Override protected void engineSetSeed(byte[] seed) { return; } private volatile boolean inCall = false; + @Override protected void engineNextBytes(byte[] bytes) { if (inCall) { diff --git a/test/jdk/javax/management/ObjectName/SerialCompatRemovedTest.java b/test/jdk/javax/management/ObjectName/SerialCompatRemovedTest.java new file mode 100644 index 00000000000..3a63e593472 --- /dev/null +++ b/test/jdk/javax/management/ObjectName/SerialCompatRemovedTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, 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 8334165 + * @summary Test that jmx.serial.form is not recognised. + * + * @run main/othervm -Djmx.serial.form=1.0 SerialCompatRemovedTest + * @run main/othervm SerialCompatRemovedTest + */ + +import java.io.*; +import java.util.*; +import javax.management.ObjectName; + +public class SerialCompatRemovedTest { + + public static void main(String[] args) throws Exception { + ObjectStreamClass osc = ObjectStreamClass.lookup(ObjectName.class); + // Serial form has no fields, uses writeObject, so we should never see + // non-zero field count here: + if (osc.getFields().length != 0) { + throw new Exception("ObjectName using old serial form?: fields: " + + Arrays.asList(osc.getFields())); + } + } +} + diff --git a/test/jdk/javax/management/ObjectName/SerialCompatTest.java b/test/jdk/javax/management/ObjectName/SerialCompatTest.java deleted file mode 100644 index 14b8720987b..00000000000 --- a/test/jdk/javax/management/ObjectName/SerialCompatTest.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 6211220 6616825 - * @summary Test that jmx.serial.form=1.0 works for ObjectName - * @author Eamonn McManus, Daniel Fuchs - * - * @run clean SerialCompatTest - * @run build SerialCompatTest - * @run main/othervm -Djdk.jmx.mbeans.allowNonPublic=true -Djmx.serial.form=1.0 SerialCompatTest - */ - -import java.io.*; -import java.util.*; -import javax.management.ObjectName; - -public class SerialCompatTest { - - public static void check6211220() throws Exception { - - ObjectName on = new ObjectName("a:b=c"); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(bos); - oos.writeObject(on); - oos.close(); - byte[] bytes = bos.toByteArray(); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bis); - ObjectName on1 = (ObjectName) ois.readObject(); - - // if the bug is present, these will get NullPointerException - for (int i = 0; i <= 11; i++) { - String msg = "6211220 case(" + i + ")"; - try { - switch (i) { - case 0: - check(msg, on1.getDomain().equals("a")); - break; - case 1: - check(msg, on1.getCanonicalName().equals("a:b=c")); - break; - case 2: - check(msg, on1.getKeyPropertyListString() - .equals("b=c")); - break; - case 3: - check(msg, on1.getCanonicalKeyPropertyListString() - .equals("b=c")); - break; - case 4: - check(msg, on1.getKeyProperty("b").equals("c")); - break; - case 5: - check(msg, on1.getKeyPropertyList() - .equals(Collections.singletonMap("b", "c"))); - break; - case 6: - check(msg, !on1.isDomainPattern()); - break; - case 7: - check(msg, !on1.isPattern()); - break; - case 8: - check(msg, !on1.isPropertyPattern()); - break; - case 9: - check(msg, on1.equals(on)); - break; - case 10: - check(msg, on.equals(on1)); - break; - case 11: - check(msg, on1.apply(on)); - break; - default: - throw new Exception(msg + ": Test incorrect"); - } - } catch (Exception e) { - System.out.println(msg + ": Test failed with exception:"); - e.printStackTrace(System.out); - failed = true; - } - } - - if (failed) { - throw new Exception("Some tests for 6211220 failed"); - } else { - System.out.println("All tests for 6211220 passed"); - } - } - - static void checkName(String testname, ObjectName on) - throws Exception { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(bos); - oos.writeObject(on); - oos.close(); - byte[] bytes = bos.toByteArray(); - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bis); - ObjectName on1 = (ObjectName) ois.readObject(); - // if the bug is present, these will get NullPointerException - for (int i = 0; i <= 11; i++) { - String msg = testname + " case(" + i + ")"; - try { - switch (i) { - case 0: - check(msg, on1.getDomain().equals(on.getDomain())); - break; - case 1: - check(msg, on1.getCanonicalName(). - equals(on.getCanonicalName())); - break; - case 2: - check(msg, on1.getKeyPropertyListString(). - equals(on.getKeyPropertyListString())); - break; - case 3: - check(msg, on1.getCanonicalKeyPropertyListString(). - equals(on.getCanonicalKeyPropertyListString())); - break; - case 4: - for (Object ko : on1.getKeyPropertyList().keySet()) { - final String key = (String) ko; - check(msg, on1.getKeyProperty(key). - equals(on.getKeyProperty(key))); - } - for (Object ko : on.getKeyPropertyList().keySet()) { - final String key = (String) ko; - check(msg, on1.getKeyProperty(key). - equals(on.getKeyProperty(key))); - } - case 5: - check(msg, on1.getKeyPropertyList() - .equals(on.getKeyPropertyList())); - break; - case 6: - check(msg, on1.isDomainPattern()==on.isDomainPattern()); - break; - case 7: - check(msg, on1.isPattern() == on.isPattern()); - break; - case 8: - check(msg, - on1.isPropertyPattern()==on.isPropertyPattern()); - break; - case 9: - check(msg, on1.equals(on)); - break; - case 10: - check(msg, on.equals(on1)); - break; - case 11: - if (!on.isPattern()) { - check(msg, on1.apply(on)); - } - break; - default: - throw new Exception("Test incorrect: case: " + i); - } - } catch (Exception e) { - System.out.println("Test (" + i + ") failed with exception:"); - e.printStackTrace(System.out); - failed = true; - } - } - - } - private static String[] names6616825 = { - "a:b=c", "a:b=c,*", "*:*", ":*", ":b=c", ":b=c,*", - "a:*,b=c", ":*", ":*,b=c", "*x?:k=\"x\\*z\"", "*x?:k=\"x\\*z\",*", - "*x?:*,k=\"x\\*z\"", "*x?:k=\"x\\*z\",*,b=c" - }; - - static void check6616825() throws Exception { - System.out.println("Testing 616825"); - for (String n : names6616825) { - final ObjectName on; - try { - on = new ObjectName(n); - } catch (Exception x) { - failed = true; - System.out.println("Unexpected failure for 6616825 [" + n + - "]: " + x); - x.printStackTrace(System.out); - continue; - } - try { - checkName("616825 " + n, on); - } catch (Exception x) { - failed = true; - System.out.println("6616825 failed for [" + n + "]: " + x); - x.printStackTrace(System.out); - } - } - - if (failed) { - throw new Exception("Some tests for 6616825 failed"); - } else { - System.out.println("All tests for 6616825 passed"); - } - } - - public static void main(String[] args) throws Exception { - /* Check that we really are in jmx.serial.form=1.0 mode. - The property is frozen the first time the ObjectName class - is referenced so checking that it is set to the correct - value now is not enough. */ - ObjectStreamClass osc = ObjectStreamClass.lookup(ObjectName.class); - if (osc.getFields().length != 6) { - throw new Exception("Not using old serial form: fields: " + - Arrays.asList(osc.getFields())); - // new serial form has no fields, uses writeObject - } - - try { - check6211220(); - } catch (Exception x) { - System.err.println(x.getMessage()); - } - try { - check6616825(); - } catch (Exception x) { - System.err.println(x.getMessage()); - } - - if (failed) { - throw new Exception("Some tests failed"); - } else { - System.out.println("All tests passed"); - } - } - - private static void check(String msg, boolean condition) { - if (!condition) { - new Throwable("Test failed " + msg).printStackTrace(System.out); - failed = true; - } - } - private static boolean failed; -} diff --git a/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java b/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java index 4ec95fb7535..c16fe0e5a82 100644 --- a/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java +++ b/test/jdk/javax/print/PrintServiceLookup/FlushCustomClassLoader.java @@ -36,7 +36,7 @@ * @summary Tests custom class loader cleanup * @library /javax/swing/regtesthelpers * @build Util - * @run main/timeout=60/othervm -mx32m FlushCustomClassLoader + * @run main/timeout=60/othervm -Xmx32m FlushCustomClassLoader */ public final class FlushCustomClassLoader { diff --git a/test/jdk/javax/sound/sampled/Clip/AudioContentHandlers.java b/test/jdk/javax/sound/sampled/Clip/AudioContentHandlers.java index c287ee061db..cb0875a5320 100644 --- a/test/jdk/javax/sound/sampled/Clip/AudioContentHandlers.java +++ b/test/jdk/javax/sound/sampled/Clip/AudioContentHandlers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -46,7 +46,7 @@ * @test * @bug 8204454 * @summary URL.getContent() should return AudioClip for supported formats - * @run main/othervm -mx128m AudioContentHandlers + * @run main/othervm -Xmx128m AudioContentHandlers */ public final class AudioContentHandlers { diff --git a/test/jdk/javax/swing/JFileChooser/6396844/TwentyThousandTest.java b/test/jdk/javax/swing/JFileChooser/6396844/TwentyThousandTest.java index afc2fc41bc4..757d21278b1 100644 --- a/test/jdk/javax/swing/JFileChooser/6396844/TwentyThousandTest.java +++ b/test/jdk/javax/swing/JFileChooser/6396844/TwentyThousandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -30,7 +30,7 @@ * @library ../../regtesthelpers * @modules java.desktop/sun.java2d * @build Util - * @run main/othervm/timeout=1000 -mx128m TwentyThousandTest + * @run main/othervm/timeout=1000 -Xmx128m TwentyThousandTest */ import sun.java2d.Disposer; diff --git a/test/jdk/javax/swing/JOptionPane/6464022/bug6464022.java b/test/jdk/javax/swing/JOptionPane/6464022/bug6464022.java index 8b3a8a07531..152bc7eecbf 100644 --- a/test/jdk/javax/swing/JOptionPane/6464022/bug6464022.java +++ b/test/jdk/javax/swing/JOptionPane/6464022/bug6464022.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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,7 +29,7 @@ * @author Pavel Porvatov * @library ../../regtesthelpers * @build Util - * @run main/othervm -mx128m bug6464022 + * @run main/othervm -Xmx128m bug6464022 */ import javax.swing.*; diff --git a/test/jdk/javax/swing/UIDefaults/6795356/bug6795356.java b/test/jdk/javax/swing/UIDefaults/6795356/bug6795356.java index 7be773a2c63..7ff527cc19d 100644 --- a/test/jdk/javax/swing/UIDefaults/6795356/bug6795356.java +++ b/test/jdk/javax/swing/UIDefaults/6795356/bug6795356.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @author Alexander Potochkin * @library ../../regtesthelpers * @build Util - * @run main/othervm -mx128m bug6795356 + * @run main/othervm -Xmx128m bug6795356 */ import java.lang.ref.WeakReference; diff --git a/test/jdk/javax/swing/border/TestTitledBorderLeak.java b/test/jdk/javax/swing/border/TestTitledBorderLeak.java index 259a2f60c29..ea7c1e2a2fd 100644 --- a/test/jdk/javax/swing/border/TestTitledBorderLeak.java +++ b/test/jdk/javax/swing/border/TestTitledBorderLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ * @summary Verifies TitledBorder's memory leak * @library /javax/swing/regtesthelpers * @build Util - * @run main/timeout=60/othervm -mx32m TestTitledBorderLeak + * @run main/timeout=60/othervm -Xmx32m TestTitledBorderLeak */ public final class TestTitledBorderLeak { diff --git a/test/jdk/javax/swing/regtesthelpers/Util.java b/test/jdk/javax/swing/regtesthelpers/Util.java index 4724fa200d6..5f81384028e 100644 --- a/test/jdk/javax/swing/regtesthelpers/Util.java +++ b/test/jdk/javax/swing/regtesthelpers/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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 @@ -82,7 +82,7 @@ public static boolean compareBufferedImages(BufferedImage bufferedImage0, Buffer /** * Fills the heap until OutOfMemoryError occurs. This method is useful for * WeakReferences removing. To minimize the amount of filled memory the - * test should provide reasonable heap size via -mx option. + * test should provide reasonable heap size via -Xmx option. */ public static void generateOOME() { List bigLeak = new LinkedList(); diff --git a/test/jdk/jdk/classfile/OneToOneTest.java b/test/jdk/jdk/classfile/OneToOneTest.java index 4e21cbebbe3..779e357ff9b 100644 --- a/test/jdk/jdk/classfile/OneToOneTest.java +++ b/test/jdk/jdk/classfile/OneToOneTest.java @@ -24,16 +24,11 @@ /* * @test * @summary Testing ClassFile class writing and reading. + * @bug 8339368 * @run junit OneToOneTest */ import java.lang.constant.ClassDesc; - -import static java.lang.classfile.ClassFile.ACC_PUBLIC; -import static java.lang.classfile.ClassFile.ACC_STATIC; -import static java.lang.constant.ConstantDescs.*; import java.lang.constant.MethodTypeDesc; -import java.util.List; - import java.lang.reflect.AccessFlag; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; @@ -41,22 +36,20 @@ import java.lang.classfile.Label; import java.lang.classfile.MethodModel; import java.lang.classfile.attribute.SourceFileAttribute; -import static org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.Test; +import java.lang.classfile.instruction.*; +import java.util.List; -import java.lang.classfile.instruction.ConstantInstruction; -import java.lang.classfile.instruction.StoreInstruction; -import java.lang.classfile.instruction.BranchInstruction; -import java.lang.classfile.instruction.LoadInstruction; -import java.lang.classfile.instruction.OperatorInstruction; -import java.lang.classfile.instruction.FieldInstruction; -import java.lang.classfile.instruction.InvokeInstruction; +import org.junit.jupiter.api.Test; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.Opcode.*; +import static java.lang.constant.ConstantDescs.*; import static helpers.TestConstants.CD_PrintStream; import static helpers.TestConstants.CD_System; import static helpers.TestConstants.MTD_INT_VOID; import static helpers.TestConstants.MTD_VOID; -import static java.lang.classfile.Opcode.*; +import static org.junit.jupiter.api.Assertions.*; class OneToOneTest { @@ -156,4 +149,36 @@ void testClassWriteRead() { } assertTrue(found); } + + @Test + void testJava5ClassWriteRead() { + MethodModel mm = ClassFile.of().parse(ClassFile.of().build(ClassDesc.of("MyClass"), clb -> clb + .withVersion(ClassFile.JAVA_5_VERSION, 0) + .withMethodBody("switches", MTD_void, ACC_STATIC, cob -> { + Label l1 = cob.newLabel(), l2 = cob.newLabel(), l3 = cob.newLabel(), l4 = cob.newLabel(); + cob.iconst_0() + .tableswitch(l1, List.of(SwitchCase.of(0, l2))) + .labelBinding(l1) + .nop() + .labelBinding(l2) + .iconst_0() + .lookupswitch(l3, List.of(SwitchCase.of(0, l4))) + .labelBinding(l3) + .nop() + .labelBinding(l4) + .return_(); + }))).methods().getFirst(); + var it = mm.code().orElseThrow().iterator(); + while (!(it.next() instanceof ConstantInstruction)); + assertTrue(it.next() instanceof TableSwitchInstruction tsi + && it.next() instanceof LabelTarget lt1 && lt1.label().equals(tsi.defaultTarget()) + && it.next() instanceof NopInstruction + && it.next() instanceof LabelTarget lt2 && lt2.label().equals(tsi.cases().getFirst().target()) + && it.next() instanceof ConstantInstruction + && it.next() instanceof LookupSwitchInstruction lsi + && it.next() instanceof LabelTarget lt3 && lt3.label().equals(lsi.defaultTarget()) + && it.next() instanceof NopInstruction + && it.next() instanceof LabelTarget lt4 && lt4.label().equals(lsi.cases().getFirst().target()), + () -> mm.code().get().elementList().toString()); + } } diff --git a/test/jdk/jdk/classfile/UtilTest.java b/test/jdk/jdk/classfile/UtilTest.java index 5ed04180919..d9d8240ae91 100644 --- a/test/jdk/jdk/classfile/UtilTest.java +++ b/test/jdk/jdk/classfile/UtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,14 @@ * @summary Testing ClassFile Util. * @run junit UtilTest */ +import java.lang.classfile.ClassFile; +import java.lang.classfile.Opcode; import java.lang.constant.MethodTypeDesc; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.BitSet; + +import jdk.internal.classfile.impl.RawBytecodeHelper; import jdk.internal.classfile.impl.Util; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -76,4 +83,21 @@ void testParameterSlots() { private void assertSlots(String methodDesc, int slots) { assertEquals(Util.parameterSlots(MethodTypeDesc.ofDescriptor(methodDesc)), slots); } + + @Test + void testOpcodeLengthTable() { + var lengths = new byte[0x100]; + Arrays.fill(lengths, (byte) -1); + for (var op : Opcode.values()) { + if (!op.isWide()) { + lengths[op.bytecode()] = (byte) op.sizeIfFixed(); + } else { + // Wide pseudo-opcodes have double the length as normal variants + // Must match logic in checkSpecialInstruction() + assertEquals(op.sizeIfFixed(), lengths[op.bytecode() & 0xFF] * 2, op + " size"); + } + } + + assertArrayEquals(lengths, RawBytecodeHelper.LENGTHS); + } } diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 11f45b24c8e..77d0dd20974 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -67,6 +67,14 @@ public class Byte128VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); + static void assertArraysStrictlyEquals(byte[] r, byte[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { byte apply(byte a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(byte[] r, byte[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, byte - interface FBinArrayOp { - byte apply(byte[] a, int b); - } - - static void assertArraysEquals(byte[] r, byte[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { byte[] apply(byte[] a, int ix, int[] b, int iy); } @@ -1212,10 +1186,6 @@ static byte cornerCaseValue(int i) { } } - static byte get(byte[] a, int i) { - return (byte) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new byte[length]; @@ -3748,22 +3718,23 @@ static void allTrueByte128VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Byte128VectorTests::allTrue); } - @Test(dataProvider = "byteUnaryOpProvider") - static void withByte128VectorTests(IntFunction fa) { + @Test(dataProvider = "byteBinaryOpProvider") + static void withByte128VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(byte a) { @@ -4698,7 +4669,7 @@ static void getByte128VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Byte128VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "byteUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index c050ab1daa8..31e38f633ff 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -67,6 +67,14 @@ public class Byte256VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); + static void assertArraysStrictlyEquals(byte[] r, byte[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { byte apply(byte a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(byte[] r, byte[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, byte - interface FBinArrayOp { - byte apply(byte[] a, int b); - } - - static void assertArraysEquals(byte[] r, byte[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { byte[] apply(byte[] a, int ix, int[] b, int iy); } @@ -1212,10 +1186,6 @@ static byte cornerCaseValue(int i) { } } - static byte get(byte[] a, int i) { - return (byte) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new byte[length]; @@ -3748,22 +3718,23 @@ static void allTrueByte256VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Byte256VectorTests::allTrue); } - @Test(dataProvider = "byteUnaryOpProvider") - static void withByte256VectorTests(IntFunction fa) { + @Test(dataProvider = "byteBinaryOpProvider") + static void withByte256VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(byte a) { @@ -4698,7 +4669,7 @@ static void getByte256VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Byte256VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "byteUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 4498714a170..9204c3ed1ad 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -67,6 +67,14 @@ public class Byte512VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); + static void assertArraysStrictlyEquals(byte[] r, byte[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { byte apply(byte a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(byte[] r, byte[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, byte - interface FBinArrayOp { - byte apply(byte[] a, int b); - } - - static void assertArraysEquals(byte[] r, byte[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { byte[] apply(byte[] a, int ix, int[] b, int iy); } @@ -1212,10 +1186,6 @@ static byte cornerCaseValue(int i) { } } - static byte get(byte[] a, int i) { - return (byte) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new byte[length]; @@ -3748,22 +3718,23 @@ static void allTrueByte512VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Byte512VectorTests::allTrue); } - @Test(dataProvider = "byteUnaryOpProvider") - static void withByte512VectorTests(IntFunction fa) { + @Test(dataProvider = "byteBinaryOpProvider") + static void withByte512VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(byte a) { @@ -4698,7 +4669,7 @@ static void getByte512VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Byte512VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "byteUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 9fb90a5fdd3..9af640a3133 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -67,6 +67,14 @@ public class Byte64VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); + static void assertArraysStrictlyEquals(byte[] r, byte[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { byte apply(byte a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(byte[] r, byte[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, byte - interface FBinArrayOp { - byte apply(byte[] a, int b); - } - - static void assertArraysEquals(byte[] r, byte[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { byte[] apply(byte[] a, int ix, int[] b, int iy); } @@ -1212,10 +1186,6 @@ static byte cornerCaseValue(int i) { } } - static byte get(byte[] a, int i) { - return (byte) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new byte[length]; @@ -3748,22 +3718,23 @@ static void allTrueByte64VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Byte64VectorTests::allTrue); } - @Test(dataProvider = "byteUnaryOpProvider") - static void withByte64VectorTests(IntFunction fa) { + @Test(dataProvider = "byteBinaryOpProvider") + static void withByte64VectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(byte a) { @@ -4698,7 +4669,7 @@ static void getByte64VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Byte64VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "byteUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 44b47293444..1c0d5362b53 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -72,6 +72,14 @@ static VectorShape getMaxBit() { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); + static void assertArraysStrictlyEquals(byte[] r, byte[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { byte apply(byte a); } @@ -236,25 +244,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(byte[] r, byte[] a, byte element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(byte[] r, byte[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -709,21 +698,6 @@ static void assertDoubleBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, byte - interface FBinArrayOp { - byte apply(byte[] a, int b); - } - - static void assertArraysEquals(byte[] r, byte[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { byte[] apply(byte[] a, int ix, int[] b, int iy); } @@ -1217,10 +1191,6 @@ static byte cornerCaseValue(int i) { } } - static byte get(byte[] a, int i) { - return (byte) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new byte[length]; @@ -3753,22 +3723,23 @@ static void allTrueByteMaxVectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, ByteMaxVectorTests::allTrue); } - @Test(dataProvider = "byteUnaryOpProvider") - static void withByteMaxVectorTests(IntFunction fa) { + @Test(dataProvider = "byteBinaryOpProvider") + static void withByteMaxVectorTests(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); + byte[] b = fb.apply(SPECIES.length()); byte[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (byte)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (byte)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(byte a) { @@ -4703,7 +4674,7 @@ static void getByteMaxVectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, ByteMaxVectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "byteUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 81c915ba7cf..4efeb8f2059 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -71,6 +71,16 @@ public class Double128VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); + static void assertArraysStrictlyEquals(double[] r, double[] a) { + for (int i = 0; i < a.length; i++) { + long ir = Double.doubleToRawLongBits(r[i]); + long ia = Double.doubleToRawLongBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %016X, actual = %016X", i, ia, ir)); + } + } + } + interface FUnOp { double apply(double a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(double[] r, double[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(double[] r, double[] a, doub } } - interface FBinArrayOp { - double apply(double[] a, int b); - } - - static void assertArraysEquals(double[] r, double[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { double[] apply(double[] a, int ix, int[] b, int iy); } @@ -1356,26 +1332,16 @@ static double[] fill(double[] a, ToDoubleF f) { } static double cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Double.MAX_VALUE; - case 1: - return Double.MIN_VALUE; - case 2: - return Double.NEGATIVE_INFINITY; - case 3: - return Double.POSITIVE_INFINITY; - case 4: - return Double.NaN; - case 5: - return (double)0.0; - default: - return (double)-0.0; - } - } - - static double get(double[] a, int i) { - return (double) a[i]; + return switch(i % 8) { + case 0 -> Double.MAX_VALUE; + case 1 -> Double.MIN_VALUE; + case 2 -> Double.NEGATIVE_INFINITY; + case 3 -> Double.POSITIVE_INFINITY; + case 4 -> Double.NaN; + case 5 -> Double.longBitsToDouble(0x7FF123456789ABCDL); + case 6 -> (double)0.0; + default -> (double)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2602,22 +2568,23 @@ static void FIRST_NONZEROReduceDouble128VectorTestsMasked(IntFunction Double128VectorTests::FIRST_NONZEROReduceMasked, Double128VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "doubleUnaryOpProvider") - static void withDouble128VectorTests(IntFunction fa) { + @Test(dataProvider = "doubleBinaryOpProvider") + static void withDouble128VectorTests(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(double a) { @@ -3507,7 +3474,7 @@ static void getDouble128VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Double128VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "doubleUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 5824941d806..04b0e7dc0d6 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -71,6 +71,16 @@ public class Double256VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); + static void assertArraysStrictlyEquals(double[] r, double[] a) { + for (int i = 0; i < a.length; i++) { + long ir = Double.doubleToRawLongBits(r[i]); + long ia = Double.doubleToRawLongBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %016X, actual = %016X", i, ia, ir)); + } + } + } + interface FUnOp { double apply(double a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(double[] r, double[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(double[] r, double[] a, doub } } - interface FBinArrayOp { - double apply(double[] a, int b); - } - - static void assertArraysEquals(double[] r, double[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { double[] apply(double[] a, int ix, int[] b, int iy); } @@ -1356,26 +1332,16 @@ static double[] fill(double[] a, ToDoubleF f) { } static double cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Double.MAX_VALUE; - case 1: - return Double.MIN_VALUE; - case 2: - return Double.NEGATIVE_INFINITY; - case 3: - return Double.POSITIVE_INFINITY; - case 4: - return Double.NaN; - case 5: - return (double)0.0; - default: - return (double)-0.0; - } - } - - static double get(double[] a, int i) { - return (double) a[i]; + return switch(i % 8) { + case 0 -> Double.MAX_VALUE; + case 1 -> Double.MIN_VALUE; + case 2 -> Double.NEGATIVE_INFINITY; + case 3 -> Double.POSITIVE_INFINITY; + case 4 -> Double.NaN; + case 5 -> Double.longBitsToDouble(0x7FF123456789ABCDL); + case 6 -> (double)0.0; + default -> (double)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2602,22 +2568,23 @@ static void FIRST_NONZEROReduceDouble256VectorTestsMasked(IntFunction Double256VectorTests::FIRST_NONZEROReduceMasked, Double256VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "doubleUnaryOpProvider") - static void withDouble256VectorTests(IntFunction fa) { + @Test(dataProvider = "doubleBinaryOpProvider") + static void withDouble256VectorTests(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(double a) { @@ -3507,7 +3474,7 @@ static void getDouble256VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Double256VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "doubleUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 895cf243eb7..ad03b8b5c7b 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -71,6 +71,16 @@ public class Double512VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); + static void assertArraysStrictlyEquals(double[] r, double[] a) { + for (int i = 0; i < a.length; i++) { + long ir = Double.doubleToRawLongBits(r[i]); + long ia = Double.doubleToRawLongBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %016X, actual = %016X", i, ia, ir)); + } + } + } + interface FUnOp { double apply(double a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(double[] r, double[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(double[] r, double[] a, doub } } - interface FBinArrayOp { - double apply(double[] a, int b); - } - - static void assertArraysEquals(double[] r, double[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { double[] apply(double[] a, int ix, int[] b, int iy); } @@ -1356,26 +1332,16 @@ static double[] fill(double[] a, ToDoubleF f) { } static double cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Double.MAX_VALUE; - case 1: - return Double.MIN_VALUE; - case 2: - return Double.NEGATIVE_INFINITY; - case 3: - return Double.POSITIVE_INFINITY; - case 4: - return Double.NaN; - case 5: - return (double)0.0; - default: - return (double)-0.0; - } - } - - static double get(double[] a, int i) { - return (double) a[i]; + return switch(i % 8) { + case 0 -> Double.MAX_VALUE; + case 1 -> Double.MIN_VALUE; + case 2 -> Double.NEGATIVE_INFINITY; + case 3 -> Double.POSITIVE_INFINITY; + case 4 -> Double.NaN; + case 5 -> Double.longBitsToDouble(0x7FF123456789ABCDL); + case 6 -> (double)0.0; + default -> (double)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2602,22 +2568,23 @@ static void FIRST_NONZEROReduceDouble512VectorTestsMasked(IntFunction Double512VectorTests::FIRST_NONZEROReduceMasked, Double512VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "doubleUnaryOpProvider") - static void withDouble512VectorTests(IntFunction fa) { + @Test(dataProvider = "doubleBinaryOpProvider") + static void withDouble512VectorTests(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(double a) { @@ -3507,7 +3474,7 @@ static void getDouble512VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Double512VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "doubleUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 4414e36b0de..9321215c3de 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -71,6 +71,16 @@ public class Double64VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); + static void assertArraysStrictlyEquals(double[] r, double[] a) { + for (int i = 0; i < a.length; i++) { + long ir = Double.doubleToRawLongBits(r[i]); + long ia = Double.doubleToRawLongBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %016X, actual = %016X", i, ia, ir)); + } + } + } + interface FUnOp { double apply(double a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(double[] r, double[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(double[] r, double[] a, doub } } - interface FBinArrayOp { - double apply(double[] a, int b); - } - - static void assertArraysEquals(double[] r, double[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { double[] apply(double[] a, int ix, int[] b, int iy); } @@ -1356,26 +1332,16 @@ static double[] fill(double[] a, ToDoubleF f) { } static double cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Double.MAX_VALUE; - case 1: - return Double.MIN_VALUE; - case 2: - return Double.NEGATIVE_INFINITY; - case 3: - return Double.POSITIVE_INFINITY; - case 4: - return Double.NaN; - case 5: - return (double)0.0; - default: - return (double)-0.0; - } - } - - static double get(double[] a, int i) { - return (double) a[i]; + return switch(i % 8) { + case 0 -> Double.MAX_VALUE; + case 1 -> Double.MIN_VALUE; + case 2 -> Double.NEGATIVE_INFINITY; + case 3 -> Double.POSITIVE_INFINITY; + case 4 -> Double.NaN; + case 5 -> Double.longBitsToDouble(0x7FF123456789ABCDL); + case 6 -> (double)0.0; + default -> (double)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2602,22 +2568,23 @@ static void FIRST_NONZEROReduceDouble64VectorTestsMasked(IntFunction f Double64VectorTests::FIRST_NONZEROReduceMasked, Double64VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "doubleUnaryOpProvider") - static void withDouble64VectorTests(IntFunction fa) { + @Test(dataProvider = "doubleBinaryOpProvider") + static void withDouble64VectorTests(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(double a) { @@ -3507,7 +3474,7 @@ static void getDouble64VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Double64VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "doubleUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 271d1f12aba..a6b80376196 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -76,6 +76,16 @@ static VectorShape getMaxBit() { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); + static void assertArraysStrictlyEquals(double[] r, double[] a) { + for (int i = 0; i < a.length; i++) { + long ir = Double.doubleToRawLongBits(r[i]); + long ia = Double.doubleToRawLongBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %016X, actual = %016X", i, ia, ir)); + } + } + } + interface FUnOp { double apply(double a); } @@ -253,25 +263,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(double[] r, double[] a, double element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(double[] r, double[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -800,21 +791,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(double[] r, double[] a, doub } } - interface FBinArrayOp { - double apply(double[] a, int b); - } - - static void assertArraysEquals(double[] r, double[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { double[] apply(double[] a, int ix, int[] b, int iy); } @@ -1361,26 +1337,16 @@ static double[] fill(double[] a, ToDoubleF f) { } static double cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Double.MAX_VALUE; - case 1: - return Double.MIN_VALUE; - case 2: - return Double.NEGATIVE_INFINITY; - case 3: - return Double.POSITIVE_INFINITY; - case 4: - return Double.NaN; - case 5: - return (double)0.0; - default: - return (double)-0.0; - } - } - - static double get(double[] a, int i) { - return (double) a[i]; + return switch(i % 8) { + case 0 -> Double.MAX_VALUE; + case 1 -> Double.MIN_VALUE; + case 2 -> Double.NEGATIVE_INFINITY; + case 3 -> Double.POSITIVE_INFINITY; + case 4 -> Double.NaN; + case 5 -> Double.longBitsToDouble(0x7FF123456789ABCDL); + case 6 -> (double)0.0; + default -> (double)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2607,22 +2573,23 @@ static void FIRST_NONZEROReduceDoubleMaxVectorTestsMasked(IntFunction DoubleMaxVectorTests::FIRST_NONZEROReduceMasked, DoubleMaxVectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "doubleUnaryOpProvider") - static void withDoubleMaxVectorTests(IntFunction fa) { + @Test(dataProvider = "doubleBinaryOpProvider") + static void withDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); + double[] b = fb.apply(SPECIES.length()); double[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (double)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (double)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(double a) { @@ -3512,7 +3479,7 @@ static void getDoubleMaxVectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, DoubleMaxVectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "doubleUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index a634aeffe54..6bad9098544 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -71,6 +71,16 @@ public class Float128VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); + static void assertArraysStrictlyEquals(float[] r, float[] a) { + for (int i = 0; i < a.length; i++) { + int ir = Float.floatToRawIntBits(r[i]); + int ia = Float.floatToRawIntBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %08X, actual = %08X", i, ia, ir)); + } + } + } + interface FUnOp { float apply(float a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(float[] r, float[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(float[] r, float[] a, float[ } } - interface FBinArrayOp { - float apply(float[] a, int b); - } - - static void assertArraysEquals(float[] r, float[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { float[] apply(float[] a, int ix, int[] b, int iy); } @@ -1367,26 +1343,16 @@ static float[] fill(float[] a, ToFloatF f) { } static float cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Float.MAX_VALUE; - case 1: - return Float.MIN_VALUE; - case 2: - return Float.NEGATIVE_INFINITY; - case 3: - return Float.POSITIVE_INFINITY; - case 4: - return Float.NaN; - case 5: - return (float)0.0; - default: - return (float)-0.0; - } - } - - static float get(float[] a, int i) { - return (float) a[i]; + return switch(i % 8) { + case 0 -> Float.MAX_VALUE; + case 1 -> Float.MIN_VALUE; + case 2 -> Float.NEGATIVE_INFINITY; + case 3 -> Float.POSITIVE_INFINITY; + case 4 -> Float.NaN; + case 5 -> Float.intBitsToFloat(0x7F812345); + case 6 -> (float)0.0; + default -> (float)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2613,22 +2579,23 @@ static void FIRST_NONZEROReduceFloat128VectorTestsMasked(IntFunction fa Float128VectorTests::FIRST_NONZEROReduceMasked, Float128VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "floatUnaryOpProvider") - static void withFloat128VectorTests(IntFunction fa) { + @Test(dataProvider = "floatBinaryOpProvider") + static void withFloat128VectorTests(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(float a) { @@ -3518,7 +3485,7 @@ static void getFloat128VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Float128VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "floatUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index d9509ff3152..e714ace5a78 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -71,6 +71,16 @@ public class Float256VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); + static void assertArraysStrictlyEquals(float[] r, float[] a) { + for (int i = 0; i < a.length; i++) { + int ir = Float.floatToRawIntBits(r[i]); + int ia = Float.floatToRawIntBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %08X, actual = %08X", i, ia, ir)); + } + } + } + interface FUnOp { float apply(float a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(float[] r, float[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(float[] r, float[] a, float[ } } - interface FBinArrayOp { - float apply(float[] a, int b); - } - - static void assertArraysEquals(float[] r, float[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { float[] apply(float[] a, int ix, int[] b, int iy); } @@ -1367,26 +1343,16 @@ static float[] fill(float[] a, ToFloatF f) { } static float cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Float.MAX_VALUE; - case 1: - return Float.MIN_VALUE; - case 2: - return Float.NEGATIVE_INFINITY; - case 3: - return Float.POSITIVE_INFINITY; - case 4: - return Float.NaN; - case 5: - return (float)0.0; - default: - return (float)-0.0; - } - } - - static float get(float[] a, int i) { - return (float) a[i]; + return switch(i % 8) { + case 0 -> Float.MAX_VALUE; + case 1 -> Float.MIN_VALUE; + case 2 -> Float.NEGATIVE_INFINITY; + case 3 -> Float.POSITIVE_INFINITY; + case 4 -> Float.NaN; + case 5 -> Float.intBitsToFloat(0x7F812345); + case 6 -> (float)0.0; + default -> (float)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2613,22 +2579,23 @@ static void FIRST_NONZEROReduceFloat256VectorTestsMasked(IntFunction fa Float256VectorTests::FIRST_NONZEROReduceMasked, Float256VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "floatUnaryOpProvider") - static void withFloat256VectorTests(IntFunction fa) { + @Test(dataProvider = "floatBinaryOpProvider") + static void withFloat256VectorTests(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(float a) { @@ -3518,7 +3485,7 @@ static void getFloat256VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Float256VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "floatUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index 83326abe54e..f3c5a316c79 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -71,6 +71,16 @@ public class Float512VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); + static void assertArraysStrictlyEquals(float[] r, float[] a) { + for (int i = 0; i < a.length; i++) { + int ir = Float.floatToRawIntBits(r[i]); + int ia = Float.floatToRawIntBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %08X, actual = %08X", i, ia, ir)); + } + } + } + interface FUnOp { float apply(float a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(float[] r, float[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(float[] r, float[] a, float[ } } - interface FBinArrayOp { - float apply(float[] a, int b); - } - - static void assertArraysEquals(float[] r, float[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { float[] apply(float[] a, int ix, int[] b, int iy); } @@ -1367,26 +1343,16 @@ static float[] fill(float[] a, ToFloatF f) { } static float cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Float.MAX_VALUE; - case 1: - return Float.MIN_VALUE; - case 2: - return Float.NEGATIVE_INFINITY; - case 3: - return Float.POSITIVE_INFINITY; - case 4: - return Float.NaN; - case 5: - return (float)0.0; - default: - return (float)-0.0; - } - } - - static float get(float[] a, int i) { - return (float) a[i]; + return switch(i % 8) { + case 0 -> Float.MAX_VALUE; + case 1 -> Float.MIN_VALUE; + case 2 -> Float.NEGATIVE_INFINITY; + case 3 -> Float.POSITIVE_INFINITY; + case 4 -> Float.NaN; + case 5 -> Float.intBitsToFloat(0x7F812345); + case 6 -> (float)0.0; + default -> (float)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2613,22 +2579,23 @@ static void FIRST_NONZEROReduceFloat512VectorTestsMasked(IntFunction fa Float512VectorTests::FIRST_NONZEROReduceMasked, Float512VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "floatUnaryOpProvider") - static void withFloat512VectorTests(IntFunction fa) { + @Test(dataProvider = "floatBinaryOpProvider") + static void withFloat512VectorTests(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(float a) { @@ -3518,7 +3485,7 @@ static void getFloat512VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Float512VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "floatUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index efae7f1fc3c..378c2ae783f 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -71,6 +71,16 @@ public class Float64VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); + static void assertArraysStrictlyEquals(float[] r, float[] a) { + for (int i = 0; i < a.length; i++) { + int ir = Float.floatToRawIntBits(r[i]); + int ia = Float.floatToRawIntBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %08X, actual = %08X", i, ia, ir)); + } + } + } + interface FUnOp { float apply(float a); } @@ -248,25 +258,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(float[] r, float[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -795,21 +786,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(float[] r, float[] a, float[ } } - interface FBinArrayOp { - float apply(float[] a, int b); - } - - static void assertArraysEquals(float[] r, float[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { float[] apply(float[] a, int ix, int[] b, int iy); } @@ -1367,26 +1343,16 @@ static float[] fill(float[] a, ToFloatF f) { } static float cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Float.MAX_VALUE; - case 1: - return Float.MIN_VALUE; - case 2: - return Float.NEGATIVE_INFINITY; - case 3: - return Float.POSITIVE_INFINITY; - case 4: - return Float.NaN; - case 5: - return (float)0.0; - default: - return (float)-0.0; - } - } - - static float get(float[] a, int i) { - return (float) a[i]; + return switch(i % 8) { + case 0 -> Float.MAX_VALUE; + case 1 -> Float.MIN_VALUE; + case 2 -> Float.NEGATIVE_INFINITY; + case 3 -> Float.POSITIVE_INFINITY; + case 4 -> Float.NaN; + case 5 -> Float.intBitsToFloat(0x7F812345); + case 6 -> (float)0.0; + default -> (float)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2613,22 +2579,23 @@ static void FIRST_NONZEROReduceFloat64VectorTestsMasked(IntFunction fa, Float64VectorTests::FIRST_NONZEROReduceMasked, Float64VectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "floatUnaryOpProvider") - static void withFloat64VectorTests(IntFunction fa) { + @Test(dataProvider = "floatBinaryOpProvider") + static void withFloat64VectorTests(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(float a) { @@ -3518,7 +3485,7 @@ static void getFloat64VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Float64VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "floatUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index fdd3e042f77..a2dc38413ec 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -76,6 +76,16 @@ static VectorShape getMaxBit() { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); + static void assertArraysStrictlyEquals(float[] r, float[] a) { + for (int i = 0; i < a.length; i++) { + int ir = Float.floatToRawIntBits(r[i]); + int ia = Float.floatToRawIntBits(a[i]); + if (ir != ia) { + Assert.fail(String.format("at index #%d, expected = %08X, actual = %08X", i, ia, ir)); + } + } + } + interface FUnOp { float apply(float a); } @@ -253,25 +263,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(float[] r, float[] a, float element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(float[] r, float[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -800,21 +791,6 @@ static void assertBroadcastArraysEqualsWithinOneUlp(float[] r, float[] a, float[ } } - interface FBinArrayOp { - float apply(float[] a, int b); - } - - static void assertArraysEquals(float[] r, float[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { float[] apply(float[] a, int ix, int[] b, int iy); } @@ -1372,26 +1348,16 @@ static float[] fill(float[] a, ToFloatF f) { } static float cornerCaseValue(int i) { - switch(i % 7) { - case 0: - return Float.MAX_VALUE; - case 1: - return Float.MIN_VALUE; - case 2: - return Float.NEGATIVE_INFINITY; - case 3: - return Float.POSITIVE_INFINITY; - case 4: - return Float.NaN; - case 5: - return (float)0.0; - default: - return (float)-0.0; - } - } - - static float get(float[] a, int i) { - return (float) a[i]; + return switch(i % 8) { + case 0 -> Float.MAX_VALUE; + case 1 -> Float.MIN_VALUE; + case 2 -> Float.NEGATIVE_INFINITY; + case 3 -> Float.POSITIVE_INFINITY; + case 4 -> Float.NaN; + case 5 -> Float.intBitsToFloat(0x7F812345); + case 6 -> (float)0.0; + default -> (float)-0.0; + }; } static final IntFunction fr = (vl) -> { @@ -2618,22 +2584,23 @@ static void FIRST_NONZEROReduceFloatMaxVectorTestsMasked(IntFunction fa FloatMaxVectorTests::FIRST_NONZEROReduceMasked, FloatMaxVectorTests::FIRST_NONZEROReduceAllMasked); } - @Test(dataProvider = "floatUnaryOpProvider") - static void withFloatMaxVectorTests(IntFunction fa) { + @Test(dataProvider = "floatBinaryOpProvider") + static void withFloatMaxVectorTests(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); + float[] b = fb.apply(SPECIES.length()); float[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (float)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (float)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(float a) { @@ -3523,7 +3490,7 @@ static void getFloatMaxVectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, FloatMaxVectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "floatUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 25d656af7da..1ee0bbc3197 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -67,6 +67,14 @@ public class Int128VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); + static void assertArraysStrictlyEquals(int[] r, int[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { int apply(int a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(int[] r, int[] a, int[] b, int[] c - interface FBinArrayOp { - int apply(int[] a, int b); - } - - static void assertArraysEquals(int[] r, int[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { int[] apply(int[] a, int ix, int[] b, int iy); } @@ -1172,10 +1146,6 @@ static int cornerCaseValue(int i) { } } - static int get(int[] a, int i) { - return (int) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new int[length]; @@ -3792,22 +3762,23 @@ static void allTrueInt128VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Int128VectorTests::allTrue); } - @Test(dataProvider = "intUnaryOpProvider") - static void withInt128VectorTests(IntFunction fa) { + @Test(dataProvider = "intBinaryOpProvider") + static void withInt128VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(int a) { @@ -4742,7 +4713,7 @@ static void getInt128VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Int128VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "intUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index 7420c7842d5..5257af21c94 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -67,6 +67,14 @@ public class Int256VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); + static void assertArraysStrictlyEquals(int[] r, int[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { int apply(int a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(int[] r, int[] a, int[] b, int[] c - interface FBinArrayOp { - int apply(int[] a, int b); - } - - static void assertArraysEquals(int[] r, int[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { int[] apply(int[] a, int ix, int[] b, int iy); } @@ -1172,10 +1146,6 @@ static int cornerCaseValue(int i) { } } - static int get(int[] a, int i) { - return (int) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new int[length]; @@ -3792,22 +3762,23 @@ static void allTrueInt256VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Int256VectorTests::allTrue); } - @Test(dataProvider = "intUnaryOpProvider") - static void withInt256VectorTests(IntFunction fa) { + @Test(dataProvider = "intBinaryOpProvider") + static void withInt256VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(int a) { @@ -4742,7 +4713,7 @@ static void getInt256VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Int256VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "intUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index ccd2bb7a5c9..6d4633cc7ae 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -67,6 +67,14 @@ public class Int512VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); + static void assertArraysStrictlyEquals(int[] r, int[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { int apply(int a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(int[] r, int[] a, int[] b, int[] c - interface FBinArrayOp { - int apply(int[] a, int b); - } - - static void assertArraysEquals(int[] r, int[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { int[] apply(int[] a, int ix, int[] b, int iy); } @@ -1172,10 +1146,6 @@ static int cornerCaseValue(int i) { } } - static int get(int[] a, int i) { - return (int) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new int[length]; @@ -3792,22 +3762,23 @@ static void allTrueInt512VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Int512VectorTests::allTrue); } - @Test(dataProvider = "intUnaryOpProvider") - static void withInt512VectorTests(IntFunction fa) { + @Test(dataProvider = "intBinaryOpProvider") + static void withInt512VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(int a) { @@ -4742,7 +4713,7 @@ static void getInt512VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Int512VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "intUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 26201745ad4..7bd1543ed5c 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -67,6 +67,14 @@ public class Int64VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); + static void assertArraysStrictlyEquals(int[] r, int[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { int apply(int a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(int[] r, int[] a, int[] b, int[] c - interface FBinArrayOp { - int apply(int[] a, int b); - } - - static void assertArraysEquals(int[] r, int[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { int[] apply(int[] a, int ix, int[] b, int iy); } @@ -1172,10 +1146,6 @@ static int cornerCaseValue(int i) { } } - static int get(int[] a, int i) { - return (int) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new int[length]; @@ -3792,22 +3762,23 @@ static void allTrueInt64VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Int64VectorTests::allTrue); } - @Test(dataProvider = "intUnaryOpProvider") - static void withInt64VectorTests(IntFunction fa) { + @Test(dataProvider = "intBinaryOpProvider") + static void withInt64VectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(int a) { @@ -4742,7 +4713,7 @@ static void getInt64VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Int64VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "intUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 612dc5080e2..71d1ce594f9 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -72,6 +72,14 @@ static VectorShape getMaxBit() { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); + static void assertArraysStrictlyEquals(int[] r, int[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { int apply(int a); } @@ -236,25 +244,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(int[] r, int[] a, int element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(int[] r, int[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -709,21 +698,6 @@ static void assertDoubleBroadcastArraysEquals(int[] r, int[] a, int[] b, int[] c - interface FBinArrayOp { - int apply(int[] a, int b); - } - - static void assertArraysEquals(int[] r, int[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { int[] apply(int[] a, int ix, int[] b, int iy); } @@ -1177,10 +1151,6 @@ static int cornerCaseValue(int i) { } } - static int get(int[] a, int i) { - return (int) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new int[length]; @@ -3797,22 +3767,23 @@ static void allTrueIntMaxVectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, IntMaxVectorTests::allTrue); } - @Test(dataProvider = "intUnaryOpProvider") - static void withIntMaxVectorTests(IntFunction fa) { + @Test(dataProvider = "intBinaryOpProvider") + static void withIntMaxVectorTests(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); + int[] b = fb.apply(SPECIES.length()); int[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (int)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (int)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(int a) { @@ -4747,7 +4718,7 @@ static void getIntMaxVectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, IntMaxVectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "intUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index 5ebc7f2c673..bcec2dee9fe 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -67,6 +67,14 @@ public class Long128VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); + static void assertArraysStrictlyEquals(long[] r, long[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { long apply(long a); } @@ -188,25 +196,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(long[] r, long[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -661,21 +650,6 @@ static void assertDoubleBroadcastArraysEquals(long[] r, long[] a, long[] b, long - interface FBinArrayOp { - long apply(long[] a, int b); - } - - static void assertArraysEquals(long[] r, long[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { long[] apply(long[] a, int ix, int[] b, int iy); } @@ -1199,10 +1173,6 @@ static long cornerCaseValue(int i) { } } - static long get(long[] a, int i) { - return (long) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new long[length]; @@ -3814,22 +3784,23 @@ static void allTrueLong128VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Long128VectorTests::allTrue); } - @Test(dataProvider = "longUnaryOpProvider") - static void withLong128VectorTests(IntFunction fa) { + @Test(dataProvider = "longBinaryOpProvider") + static void withLong128VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(long a) { @@ -4694,7 +4665,7 @@ static void getLong128VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Long128VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "longUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index b7b66008917..e8f2fb1301c 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -67,6 +67,14 @@ public class Long256VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); + static void assertArraysStrictlyEquals(long[] r, long[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { long apply(long a); } @@ -188,25 +196,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(long[] r, long[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -661,21 +650,6 @@ static void assertDoubleBroadcastArraysEquals(long[] r, long[] a, long[] b, long - interface FBinArrayOp { - long apply(long[] a, int b); - } - - static void assertArraysEquals(long[] r, long[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { long[] apply(long[] a, int ix, int[] b, int iy); } @@ -1199,10 +1173,6 @@ static long cornerCaseValue(int i) { } } - static long get(long[] a, int i) { - return (long) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new long[length]; @@ -3814,22 +3784,23 @@ static void allTrueLong256VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Long256VectorTests::allTrue); } - @Test(dataProvider = "longUnaryOpProvider") - static void withLong256VectorTests(IntFunction fa) { + @Test(dataProvider = "longBinaryOpProvider") + static void withLong256VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(long a) { @@ -4694,7 +4665,7 @@ static void getLong256VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Long256VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "longUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 65edac9114c..022f1490fcc 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -67,6 +67,14 @@ public class Long512VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); + static void assertArraysStrictlyEquals(long[] r, long[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { long apply(long a); } @@ -188,25 +196,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(long[] r, long[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -661,21 +650,6 @@ static void assertDoubleBroadcastArraysEquals(long[] r, long[] a, long[] b, long - interface FBinArrayOp { - long apply(long[] a, int b); - } - - static void assertArraysEquals(long[] r, long[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { long[] apply(long[] a, int ix, int[] b, int iy); } @@ -1199,10 +1173,6 @@ static long cornerCaseValue(int i) { } } - static long get(long[] a, int i) { - return (long) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new long[length]; @@ -3814,22 +3784,23 @@ static void allTrueLong512VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Long512VectorTests::allTrue); } - @Test(dataProvider = "longUnaryOpProvider") - static void withLong512VectorTests(IntFunction fa) { + @Test(dataProvider = "longBinaryOpProvider") + static void withLong512VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(long a) { @@ -4694,7 +4665,7 @@ static void getLong512VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Long512VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "longUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index 7b1c65716aa..fe886bf93d8 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -67,6 +67,14 @@ public class Long64VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); + static void assertArraysStrictlyEquals(long[] r, long[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { long apply(long a); } @@ -188,25 +196,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(long[] r, long[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -661,21 +650,6 @@ static void assertDoubleBroadcastArraysEquals(long[] r, long[] a, long[] b, long - interface FBinArrayOp { - long apply(long[] a, int b); - } - - static void assertArraysEquals(long[] r, long[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { long[] apply(long[] a, int ix, int[] b, int iy); } @@ -1199,10 +1173,6 @@ static long cornerCaseValue(int i) { } } - static long get(long[] a, int i) { - return (long) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new long[length]; @@ -3814,22 +3784,23 @@ static void allTrueLong64VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Long64VectorTests::allTrue); } - @Test(dataProvider = "longUnaryOpProvider") - static void withLong64VectorTests(IntFunction fa) { + @Test(dataProvider = "longBinaryOpProvider") + static void withLong64VectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(long a) { @@ -4694,7 +4665,7 @@ static void getLong64VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Long64VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "longUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 06f5814e533..b77d6eeb118 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -72,6 +72,14 @@ static VectorShape getMaxBit() { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); + static void assertArraysStrictlyEquals(long[] r, long[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { long apply(long a); } @@ -193,25 +201,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(long[] r, long[] a, long element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(long[] r, long[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -666,21 +655,6 @@ static void assertDoubleBroadcastArraysEquals(long[] r, long[] a, long[] b, long - interface FBinArrayOp { - long apply(long[] a, int b); - } - - static void assertArraysEquals(long[] r, long[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { long[] apply(long[] a, int ix, int[] b, int iy); } @@ -1204,10 +1178,6 @@ static long cornerCaseValue(int i) { } } - static long get(long[] a, int i) { - return (long) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new long[length]; @@ -3819,22 +3789,23 @@ static void allTrueLongMaxVectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, LongMaxVectorTests::allTrue); } - @Test(dataProvider = "longUnaryOpProvider") - static void withLongMaxVectorTests(IntFunction fa) { + @Test(dataProvider = "longBinaryOpProvider") + static void withLongMaxVectorTests(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); + long[] b = fb.apply(SPECIES.length()); long[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (long)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (long)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(long a) { @@ -4699,7 +4670,7 @@ static void getLongMaxVectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, LongMaxVectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "longUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index c9fe21f8125..2a82ada044e 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -67,6 +67,14 @@ public class Short128VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); + static void assertArraysStrictlyEquals(short[] r, short[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { short apply(short a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(short[] r, short[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(short[] r, short[] a, short[] b, s - interface FBinArrayOp { - short apply(short[] a, int b); - } - - static void assertArraysEquals(short[] r, short[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { short[] apply(short[] a, int ix, int[] b, int iy); } @@ -1202,10 +1176,6 @@ static short cornerCaseValue(int i) { } } - static short get(short[] a, int i) { - return (short) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new short[length]; @@ -3739,22 +3709,23 @@ static void allTrueShort128VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Short128VectorTests::allTrue); } - @Test(dataProvider = "shortUnaryOpProvider") - static void withShort128VectorTests(IntFunction fa) { + @Test(dataProvider = "shortBinaryOpProvider") + static void withShort128VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(short a) { @@ -4689,7 +4660,7 @@ static void getShort128VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Short128VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "shortUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index a39ec0126d4..69a8432acef 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -67,6 +67,14 @@ public class Short256VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); + static void assertArraysStrictlyEquals(short[] r, short[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { short apply(short a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(short[] r, short[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(short[] r, short[] a, short[] b, s - interface FBinArrayOp { - short apply(short[] a, int b); - } - - static void assertArraysEquals(short[] r, short[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { short[] apply(short[] a, int ix, int[] b, int iy); } @@ -1202,10 +1176,6 @@ static short cornerCaseValue(int i) { } } - static short get(short[] a, int i) { - return (short) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new short[length]; @@ -3739,22 +3709,23 @@ static void allTrueShort256VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Short256VectorTests::allTrue); } - @Test(dataProvider = "shortUnaryOpProvider") - static void withShort256VectorTests(IntFunction fa) { + @Test(dataProvider = "shortBinaryOpProvider") + static void withShort256VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(short a) { @@ -4689,7 +4660,7 @@ static void getShort256VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Short256VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "shortUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 5453c19149c..8e892a8a48e 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -67,6 +67,14 @@ public class Short512VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); + static void assertArraysStrictlyEquals(short[] r, short[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { short apply(short a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(short[] r, short[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(short[] r, short[] a, short[] b, s - interface FBinArrayOp { - short apply(short[] a, int b); - } - - static void assertArraysEquals(short[] r, short[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { short[] apply(short[] a, int ix, int[] b, int iy); } @@ -1202,10 +1176,6 @@ static short cornerCaseValue(int i) { } } - static short get(short[] a, int i) { - return (short) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new short[length]; @@ -3739,22 +3709,23 @@ static void allTrueShort512VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Short512VectorTests::allTrue); } - @Test(dataProvider = "shortUnaryOpProvider") - static void withShort512VectorTests(IntFunction fa) { + @Test(dataProvider = "shortBinaryOpProvider") + static void withShort512VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(short a) { @@ -4689,7 +4660,7 @@ static void getShort512VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Short512VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "shortUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 8ba47569595..97658d4257d 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -67,6 +67,14 @@ public class Short64VectorTests extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); + static void assertArraysStrictlyEquals(short[] r, short[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { short apply(short a); } @@ -231,25 +239,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(short[] r, short[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -704,21 +693,6 @@ static void assertDoubleBroadcastArraysEquals(short[] r, short[] a, short[] b, s - interface FBinArrayOp { - short apply(short[] a, int b); - } - - static void assertArraysEquals(short[] r, short[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { short[] apply(short[] a, int ix, int[] b, int iy); } @@ -1202,10 +1176,6 @@ static short cornerCaseValue(int i) { } } - static short get(short[] a, int i) { - return (short) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new short[length]; @@ -3739,22 +3709,23 @@ static void allTrueShort64VectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, Short64VectorTests::allTrue); } - @Test(dataProvider = "shortUnaryOpProvider") - static void withShort64VectorTests(IntFunction fa) { + @Test(dataProvider = "shortBinaryOpProvider") + static void withShort64VectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(short a) { @@ -4689,7 +4660,7 @@ static void getShort64VectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, Short64VectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "shortUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 7b00638878d..0857c13ef3c 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -72,6 +72,14 @@ static VectorShape getMaxBit() { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); + static void assertArraysStrictlyEquals(short[] r, short[] a) { + for (int i = 0; i < a.length; i++) { + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } + } + } + interface FUnOp { short apply(short a); } @@ -236,25 +244,6 @@ static void assertMaskReductionArraysEquals(int[] r, boolean[] a, FMaskReduction } } - static void assertInsertArraysEquals(short[] r, short[] a, short element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals(short[] r, short[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -709,21 +698,6 @@ static void assertDoubleBroadcastArraysEquals(short[] r, short[] a, short[] b, s - interface FBinArrayOp { - short apply(short[] a, int b); - } - - static void assertArraysEquals(short[] r, short[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { short[] apply(short[] a, int ix, int[] b, int iy); } @@ -1207,10 +1181,6 @@ static short cornerCaseValue(int i) { } } - static short get(short[] a, int i) { - return (short) a[i]; - } - static final IntFunction fr = (vl) -> { int length = BUFFER_REPS * vl; return new short[length]; @@ -3744,22 +3714,23 @@ static void allTrueShortMaxVectorTests(IntFunction fm) { assertReductionBoolArraysEquals(r, mask, ShortMaxVectorTests::allTrue); } - @Test(dataProvider = "shortUnaryOpProvider") - static void withShortMaxVectorTests(IntFunction fa) { + @Test(dataProvider = "shortBinaryOpProvider") + static void withShortMaxVectorTests(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); + short[] b = fb.apply(SPECIES.length()); short[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); - av.withLane((j++ & (SPECIES.length()-1)), (short)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) & (SPECIES.length() - 1); } } - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, (short)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } static boolean testIS_DEFAULT(short a) { @@ -4694,7 +4665,7 @@ static void getShortMaxVectorTests(IntFunction fa) { } } - assertArraysEquals(r, a, ShortMaxVectorTests::get); + assertArraysStrictlyEquals(r, a); } @Test(dataProvider = "shortUnaryOpProvider") diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template index 95d74b84860..261535317c6 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-With-Op.template @@ -1,10 +1,13 @@ $type$[] a = fa.apply(SPECIES.length()); + $type$[] b = fb.apply(SPECIES.length()); $type$[] r = fr.apply(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); - av.withLane((j++ \& (SPECIES.length()-1)), ($type$)(65535+i)).intoArray(r, i); + av.withLane(j, b[i + j]).intoArray(r, i); + a[i + j] = b[i + j]; + j = (j + 1) \& (SPECIES.length() - 1); } } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Get-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Get-op.template index ec311693f4c..b60ff50076e 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Get-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Get-op.template @@ -2,5 +2,5 @@ @Test(dataProvider = "$type$UnaryOpProvider") static void get$vectorteststype$(IntFunction<$type$[]> fa) { [[KERNEL]] - assertArraysEquals(r, a, $vectorteststype$::get); + assertArraysStrictlyEquals(r, a); } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template b/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template index c41bd05f20e..5a889ceb8b9 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-With-Op.template @@ -1,9 +1,7 @@ - @Test(dataProvider = "$type$UnaryOpProvider") - static void with$vectorteststype$(IntFunction<$type$ []> fa) { + @Test(dataProvider = "$type$BinaryOpProvider") + static void with$vectorteststype$(IntFunction<$type$ []> fa, IntFunction<$type$ []> fb) { [[KERNEL]] - for (int i = 0, j = 0; i < a.length; i += SPECIES.length()) { - assertInsertArraysEquals(r, a, ($type$)(65535+i), (j++ & (SPECIES.length()-1)), i , i + SPECIES.length()); - } + assertArraysStrictlyEquals(r, a); } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 38ab6178244..42440881771 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -105,6 +105,26 @@ public class $vectorteststype$ extends AbstractVectorTest { static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / $bits$); + static void assertArraysStrictlyEquals($type$[] r, $type$[] a) { + for (int i = 0; i < a.length; i++) { +#if[FP] + $bitstype$ ir = $Wideboxtype$.$type$ToRaw$Bitstype$Bits(r[i]); + $bitstype$ ia = $Wideboxtype$.$type$ToRaw$Bitstype$Bits(a[i]); + if (ir != ia) { +#if[Float] + Assert.fail(String.format("at index #%d, expected = %08X, actual = %08X", i, ia, ir)); +#else[Float] + Assert.fail(String.format("at index #%d, expected = %016X, actual = %016X", i, ia, ir)); +#end[Float] + } +#else[FP] + if (r[i] != a[i]) { + Assert.fail("at index #" + i + ", expected = " + a[i] + ", actual = " + r[i]); + } +#end[FP] + } + } + interface FUnOp { $type$ apply($type$ a); } @@ -314,25 +334,6 @@ relativeError)); } } - static void assertInsertArraysEquals($type$[] r, $type$[] a, $type$ element, int index, int start, int end) { - int i = start; - try { - for (; i < end; i += 1) { - if(i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element); - } else { - Assert.assertEquals(r[i], a[i]); - } - } - } catch (AssertionError e) { - if (i%SPECIES.length() == index) { - Assert.assertEquals(r[i], element, "at index #" + i); - } else { - Assert.assertEquals(r[i], a[i], "at index #" + i); - } - } - } - static void assertRearrangeArraysEquals($type$[] r, $type$[] a, int[] order, int vector_len) { int i = 0, j = 0; try { @@ -863,21 +864,6 @@ relativeError)); } #end[FP] - interface FBinArrayOp { - $type$ apply($type$[] a, int b); - } - - static void assertArraysEquals($type$[] r, $type$[] a, FBinArrayOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a, i)); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a,i), "at index #" + i); - } - } - interface FGatherScatterOp { $type$[] apply($type$[] a, int ix, int[] b, int iy); } @@ -1472,22 +1458,20 @@ relativeError)); static $type$ cornerCaseValue(int i) { #if[FP] - switch(i % 7) { - case 0: - return $Wideboxtype$.MAX_VALUE; - case 1: - return $Wideboxtype$.MIN_VALUE; - case 2: - return $Wideboxtype$.NEGATIVE_INFINITY; - case 3: - return $Wideboxtype$.POSITIVE_INFINITY; - case 4: - return $Wideboxtype$.NaN; - case 5: - return ($type$)0.0; - default: - return ($type$)-0.0; - } + return switch(i % 8) { + case 0 -> $Wideboxtype$.MAX_VALUE; + case 1 -> $Wideboxtype$.MIN_VALUE; + case 2 -> $Wideboxtype$.NEGATIVE_INFINITY; + case 3 -> $Wideboxtype$.POSITIVE_INFINITY; + case 4 -> $Wideboxtype$.NaN; +#if[Float] + case 5 -> Float.intBitsToFloat(0x7F812345); +#else[Float] + case 5 -> Double.longBitsToDouble(0x7FF123456789ABCDL); +#end[Float] + case 6 -> ($type$)0.0; + default -> ($type$)-0.0; + }; #else[FP] switch(i % 5) { case 0: @@ -1504,10 +1488,6 @@ relativeError)); #end[FP] } - static $type$ get($type$[] a, int i) { - return ($type$) a[i]; - } - static final IntFunction<$type$[]> fr = (vl) -> { int length = BUFFER_REPS * vl; return new $type$[length]; diff --git a/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java new file mode 100644 index 00000000000..891f6e62e6f --- /dev/null +++ b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2024, 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 8338890 + * @summary Basic test for jdk.management.VirtualThreadSchedulerMXBean + * @requires vm.continuations + * @modules jdk.management + * @library /test/lib + * @run junit/othervm VirtualThreadSchedulerMXBeanTest + */ + +import java.lang.management.ManagementFactory; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; +import java.util.stream.IntStream; +import javax.management.MBeanServer; +import jdk.management.VirtualThreadSchedulerMXBean; + +import jdk.test.lib.thread.VThreadRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.*; + +class VirtualThreadSchedulerMXBeanTest { + + /** + * VirtualThreadSchedulerMXBean objects to test. + */ + private static Stream managedBeans() throws Exception { + var bean1 = ManagementFactory.getPlatformMXBean(VirtualThreadSchedulerMXBean.class); + + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + var bean2 = ManagementFactory.newPlatformMXBeanProxy(server, + "jdk.management:type=VirtualThreadScheduler", + VirtualThreadSchedulerMXBean.class); + + return Stream.of(bean1, bean2); + } + + /** + * Test default parallelism. + */ + @ParameterizedTest + @MethodSource("managedBeans") + void testDefaultParallelism(VirtualThreadSchedulerMXBean bean) { + assertEquals(Runtime.getRuntime().availableProcessors(), bean.getParallelism()); + } + + /** + * Test increasing parallelism. + */ + @ParameterizedTest + @MethodSource("managedBeans") + void testIncreaseParallelism(VirtualThreadSchedulerMXBean bean) throws Exception { + assumeFalse(Thread.currentThread().isVirtual(), "Main thread is a virtual thread"); + + final int parallelism = bean.getParallelism(); + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + var done = new AtomicBoolean(); + Runnable busyTask = () -> { + while (!done.get()) { + Thread.onSpinWait(); + } + }; + + try { + // saturate + IntStream.range(0, parallelism).forEach(_ -> executor.submit(busyTask)); + awaitPoolSizeGte(bean, parallelism); + awaitMountedVirtualThreadCountGte(bean, parallelism); + + // increase parallelism + for (int k = 1; k <= 4; k++) { + int newParallelism = parallelism + k; + bean.setParallelism(newParallelism); + executor.submit(busyTask); + + // pool size and mounted virtual thread should increase + awaitPoolSizeGte(bean, newParallelism); + awaitMountedVirtualThreadCountGte(bean, newParallelism); + } + } finally { + done.set(true); + } + } finally { + bean.setParallelism(parallelism); // restore + } + } + + /** + * Test reducing parallelism. + */ + @ParameterizedTest + @MethodSource("managedBeans") + void testReduceParallelism(VirtualThreadSchedulerMXBean bean) throws Exception { + assumeFalse(Thread.currentThread().isVirtual(), "Main thread is a virtual thread"); + + final int parallelism = bean.getParallelism(); + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + var done = new AtomicBoolean(); + var sleep = new AtomicBoolean(); + + // spin when !sleep + Runnable busyTask = () -> { + while (!done.get()) { + if (sleep.get()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { } + } else { + Thread.onSpinWait(); + } + } + }; + + try { + // increase parallelism + saturate + int newParallelism = parallelism + 4; + bean.setParallelism(newParallelism); + IntStream.range(0, newParallelism).forEach(_ -> executor.submit(busyTask)); + awaitMountedVirtualThreadCountGte(bean, newParallelism); + + // reduce parallelism and workload + newParallelism = Math.clamp(parallelism / 2, 1, parallelism); + bean.setParallelism(newParallelism); + sleep.set(true); + // mounted virtual thread count should reduce + awaitMountedVirtualThreadCountLte(bean, newParallelism); + + // increase workload, the mounted virtual thread count should not increase + sleep.set(false); + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + assertTrue(bean.getMountedVirtualThreadCount() <= newParallelism); + } + + } finally { + done.set(true); + } + } finally { + bean.setParallelism(parallelism); // restore + } + } + + /** + * Test getPoolSize. + */ + @ParameterizedTest + @MethodSource("managedBeans") + void testPoolSize(VirtualThreadSchedulerMXBean bean) { + assertTrue(bean.getPoolSize() >= 0); + VThreadRunner.run(() -> { + assertTrue(Thread.currentThread().isVirtual()); + assertTrue(bean.getPoolSize() >= 1); + }); + } + + /** + * Test getMountedVirtualThreadCount. + */ + @ParameterizedTest + @MethodSource("managedBeans") + void testMountedVirtualThreadCount(VirtualThreadSchedulerMXBean bean) { + assertTrue(bean.getMountedVirtualThreadCount() >= 0); + VThreadRunner.run(() -> { + assertTrue(Thread.currentThread().isVirtual()); + assertTrue(bean.getMountedVirtualThreadCount() >= 1); + }); + } + + /** + * Test getQueuedVirtualThreadCount. + */ + @ParameterizedTest + @MethodSource("managedBeans") + void testQueuedVirtualThreadCount(VirtualThreadSchedulerMXBean bean) throws Exception { + assumeFalse(Thread.currentThread().isVirtual(), "Main thread is a virtual thread"); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + var done = new AtomicBoolean(); + Runnable busyTask = () -> { + while (!done.get()) { + Thread.onSpinWait(); + } + }; + + try { + // saturate + int parallelism = bean.getParallelism(); + IntStream.range(0, parallelism).forEach(_ -> executor.submit(busyTask)); + awaitMountedVirtualThreadCountGte(bean, parallelism); + + // start 5 virtual threads, their tasks will be queued to execute + for (int i = 0; i < 5; i++) { + executor.submit(() -> { }); + } + assertTrue(bean.getQueuedVirtualThreadCount() >= 5); + } finally { + done.set(true); + } + } + } + + /** + * Waits for pool size >= target to be true. + */ + void awaitPoolSizeGte(VirtualThreadSchedulerMXBean bean, int target) throws InterruptedException { + System.err.format("await pool size >= %d ...%n", target); + while (bean.getPoolSize() < target) { + Thread.sleep(10); + } + } + + /** + * Waits for the mounted virtual thread count >= target to be true. + */ + void awaitMountedVirtualThreadCountGte(VirtualThreadSchedulerMXBean bean, + int target) throws InterruptedException { + System.err.format("await mounted virtual thread count >= %d ...%n", target); + while (bean.getMountedVirtualThreadCount() < target) { + Thread.sleep(10); + } + } + + /** + * Waits for the mounted virtual thread count <= target to be true. + */ + void awaitMountedVirtualThreadCountLte(VirtualThreadSchedulerMXBean bean, + int target) throws InterruptedException { + System.err.format("await mounted virtual thread count <= %d ...%n", target); + while (bean.getMountedVirtualThreadCount() > target) { + Thread.sleep(10); + } + } +} \ No newline at end of file diff --git a/test/jdk/sun/java2d/Disposer/TestDisposerLeak.java b/test/jdk/sun/java2d/Disposer/TestDisposerLeak.java index 0fcf8cdda08..bdab5ffb5fb 100644 --- a/test/jdk/sun/java2d/Disposer/TestDisposerLeak.java +++ b/test/jdk/sun/java2d/Disposer/TestDisposerLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * @test * @bug 8129457 * @summary Check Disposer disposes all objects without any memory leaks - * @run main/othervm -mx128m TestDisposerLeak + * @run main/othervm -Xmx128m TestDisposerLeak * @modules java.desktop/sun.java2d */ public final class TestDisposerLeak { diff --git a/test/jdk/sun/java2d/Disposer/TestDisposerRace.java b/test/jdk/sun/java2d/Disposer/TestDisposerRace.java index b78966f1200..cbb594d7a1f 100644 --- a/test/jdk/sun/java2d/Disposer/TestDisposerRace.java +++ b/test/jdk/sun/java2d/Disposer/TestDisposerRace.java @@ -33,7 +33,7 @@ * @test * @bug 8289208 * @summary Verifies Disposer robustness in a multi-threaded environment. - * @run main/othervm -mx128m TestDisposerRace + * @run main/othervm -Xmx128m TestDisposerRace * @modules java.desktop/sun.java2d */ public final class TestDisposerRace { diff --git a/test/jdk/sun/java2d/marlin/CrashTest.java b/test/jdk/sun/java2d/marlin/CrashTest.java index b5283fdf332..5b9632caafe 100644 --- a/test/jdk/sun/java2d/marlin/CrashTest.java +++ b/test/jdk/sun/java2d/marlin/CrashTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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,9 +35,9 @@ /** * @test * @summary Simple crash rendering test using huge GeneralPaths with the Marlin renderer - * @run main/othervm -mx512m CrashTest + * @run main/othervm -Xmx512m CrashTest * @ignore tests that take a long time and consumes 5Gb memory - * @run main/othervm -ms4g -mx4g CrashTest -slow + * @run main/othervm -Xms4g -Xmx4g CrashTest -slow */ public class CrashTest { diff --git a/test/jdk/sun/security/ec/ed/TestEdOps.java b/test/jdk/sun/security/ec/ed/TestEdOps.java index 6ef1446db46..82b7f2c507f 100644 --- a/test/jdk/sun/security/ec/ed/TestEdOps.java +++ b/test/jdk/sun/security/ec/ed/TestEdOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -40,7 +40,7 @@ import java.util.Arrays; import java.util.HexFormat; -import sun.security.provider.SHAKE256; +import sun.security.provider.SHA3.SHAKE256; public class TestEdOps { diff --git a/test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java b/test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java new file mode 100644 index 00000000000..5cdcce00e35 --- /dev/null +++ b/test/jdk/sun/security/provider/MessageDigest/SHAKEsqueeze.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024, 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 8338587 + * @summary Ensure squeeze and digest always have the same output + * @library /test/lib + * @modules java.base/sun.security.provider + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.security.SeededSecureRandom; +import sun.security.provider.SHA3; + +import java.io.ByteArrayOutputStream; +import java.util.Arrays; + +public class SHAKEsqueeze { + public static void main(String[] args) throws Exception { + var r = SeededSecureRandom.one(); + var atlast = 0; + // Random test on SHAKE + for (var i = 0; i < 1_000_000; i++) { + var s = new SHA3.SHAKE256(0); + var in = new ByteArrayOutputStream(); + while (r.nextBoolean()) { + var b = r.nBytes(r.nextInt(200)); + if (b.length > 0 && r.nextBoolean()) { + // Test update(b) + s.update(b[0]); + in.write(b[0]); + } else if (r.nextBoolean()) { + // Test update(byte[]) + s.update(b); + in.write(b); + } else { + // Test update(byte[], offset, len) + var prepend = r.nextInt(100); + var append = r.nextInt(100); + var bb = new byte[prepend + b.length + append]; + r.nextBytes(bb); + System.arraycopy(b, 0, bb, prepend, b.length); + s.update(bb, prepend, b.length); + in.write(b); + } + } + + // Squeeze for multiple times + var out = new ByteArrayOutputStream(); + do { + var n = r.nextInt(200); + out.write(s.squeeze(n)); + } while (out.size() == 0 || r.nextBoolean()); + var b1 = out.toByteArray(); + + // Digest for one time + var s2 = new SHA3.SHAKE256(b1.length); + s2.update(in.toByteArray()); + var b2 = s2.digest(); + + atlast = Arrays.hashCode(b2) * 17 + atlast; + Asserts.assertEqualsByteArray(b1, b2); + } + // Just to provide a visual clue to show that the same + // SeededSecureRandom seed results in same final result + // so that the test can be exactly reproduced. + System.out.println("Final hash: " + atlast); + } +} diff --git a/test/jdk/sun/security/provider/SecureRandom/StrongSecureRandom.java b/test/jdk/sun/security/provider/SecureRandom/StrongSecureRandom.java index bdd3ab0a4b9..1c6d515e4f0 100644 --- a/test/jdk/sun/security/provider/SecureRandom/StrongSecureRandom.java +++ b/test/jdk/sun/security/provider/SecureRandom/StrongSecureRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,16 @@ /* * @test - * @bug 6425477 8141039 + * @bug 6425477 8141039 8324648 + * @library /test/lib * @summary Better support for generation of high entropy random numbers * @run main StrongSecureRandom */ import java.security.*; import java.util.*; +import static jdk.test.lib.Asserts.assertTrue; + /** * This test assumes that the standard Sun providers are installed. */ @@ -89,6 +92,27 @@ private static void testNativePRNGImpls() throws Exception { ba = sr.generateSeed(1); sr.nextBytes(ba); sr.setSeed(ba); + + testParamsUnsupported("NativePRNG"); + testParamsUnsupported("NativePRNGNonBlocking"); + testParamsUnsupported("NativePRNGBlocking"); + } + + private static void testParamsUnsupported(String alg) throws NoSuchAlgorithmException { + System.out.println("Testing that " + alg + " does not support params"); + + try { + SecureRandom.getInstance(alg, new SecureRandomParameters() {}); + throw new RuntimeException("Params should not be supported"); + } catch (NoSuchAlgorithmException nsae) { + Throwable cause = nsae.getCause(); + if (cause instanceof IllegalArgumentException) { + assertTrue(cause.getMessage().contains("Unsupported params"), + "Unexpected error message: " + cause.getMessage()); + } else { + throw nsae; + } + } } private static void testStrongInstance(boolean expected) throws Exception { diff --git a/test/jdk/sun/security/tools/keytool/TestImportPass.java b/test/jdk/sun/security/tools/keytool/TestImportPass.java new file mode 100644 index 00000000000..adf8dba8415 --- /dev/null +++ b/test/jdk/sun/security/tools/keytool/TestImportPass.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, 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 8339347 + * @summary Test keytool -importpass with password input from System.in for + * the non-terminal console + * @library /test/lib + * @run main TestImportPass + */ + +import jdk.test.lib.SecurityTools; + +public class TestImportPass { + public static void main(String[] args) throws Throwable { + SecurityTools.setResponse("pass123"); + SecurityTools.keytool("-importpass -keystore ks.p12 -storepass changeit " + + "-storetype pkcs12 -alias newentry") + .shouldNotContain("Enter the password to be stored:") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-list -keystore ks.p12 -storepass changeit " + + "-v") + .shouldContain("Alias name: newentry") + .shouldHaveExitValue(0); + } +} diff --git a/test/jdk/sun/security/validator/samedn.sh b/test/jdk/sun/security/validator/samedn.sh index 6a30b147157..a38d6e70990 100644 --- a/test/jdk/sun/security/validator/samedn.sh +++ b/test/jdk/sun/security/validator/samedn.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -62,10 +62,11 @@ $KT -genkeypair -alias ca1 -dname CN=CA -keyalg rsa -sigalg md5withrsa -ext bc - $KT -genkeypair -alias ca2 -dname CN=CA -keyalg rsa -sigalg sha1withrsa -ext bc -startdate -1y $KT -genkeypair -alias user -dname CN=User -keyalg rsa -# 2. Signing: ca -> user +# 2. Signing: ca -> user. The startdate is set to 1 minute in the past to ensure the certificate +# is valid at the time of validation and to prevent any issues with timing discrepancies -$KT -certreq -alias user | $KT -gencert -rfc -alias ca1 > samedn1.certs -$KT -certreq -alias user | $KT -gencert -rfc -alias ca2 > samedn2.certs +$KT -certreq -alias user | $KT -gencert -rfc -alias ca1 -startdate -1M > samedn1.certs +$KT -certreq -alias user | $KT -gencert -rfc -alias ca2 -startdate -1M > samedn2.certs # 3. Append the ca file diff --git a/test/jdk/sun/util/calendar/zi/Month.java b/test/jdk/sun/util/calendar/zi/Month.java index cb60b8d4411..bab909f7637 100644 --- a/test/jdk/sun/util/calendar/zi/Month.java +++ b/test/jdk/sun/util/calendar/zi/Month.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -21,11 +21,6 @@ * questions. */ -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * Month enum handles month related manipulation. * @@ -47,15 +42,6 @@ enum Month { private final String abbr; - private static final Map abbreviations - = new HashMap(12); - - static { - for (Month m : Month.values()) { - abbreviations.put(m.abbr, m); - } - } - private Month(String abbr) { this.abbr = abbr; } @@ -70,11 +56,22 @@ int value() { * @return the Month value */ static Month parse(String name) { - Month m = abbreviations.get(name); - if (m != null) { - return m; - } - return null; + int len = name.length(); + + if (name.regionMatches(true, 0, "January", 0, len)) return Month.JANUARY; + if (name.regionMatches(true, 0, "February", 0, len)) return Month.FEBRUARY; + if (name.regionMatches(true, 0, "March", 0, len)) return Month.MARCH; + if (name.regionMatches(true, 0, "April", 0, len)) return Month.APRIL; + if (name.regionMatches(true, 0, "May", 0, len)) return Month.MAY; + if (name.regionMatches(true, 0, "June", 0, len)) return Month.JUNE; + if (name.regionMatches(true, 0, "July", 0, len)) return Month.JULY; + if (name.regionMatches(true, 0, "August", 0, len)) return Month.AUGUST; + if (name.regionMatches(true, 0, "September", 0, len)) return Month.SEPTEMBER; + if (name.regionMatches(true, 0, "October", 0, len)) return Month.OCTOBER; + if (name.regionMatches(true, 0, "November", 0, len)) return Month.NOVEMBER; + if (name.regionMatches(true, 0, "December", 0, len)) return Month.DECEMBER; + + throw new IllegalArgumentException("Unknown month: " + name); } /** diff --git a/test/jdk/sun/util/calendar/zi/RuleDay.java b/test/jdk/sun/util/calendar/zi/RuleDay.java index bc730944b4c..9cd81c1e524 100644 --- a/test/jdk/sun/util/calendar/zi/RuleDay.java +++ b/test/jdk/sun/util/calendar/zi/RuleDay.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -21,11 +21,6 @@ * questions. */ -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * RuleDay class represents the value of the "ON" field. The day of * week values start from 1 following the {@link java.util.Calendar} @@ -34,13 +29,6 @@ * @since 1.4 */ class RuleDay { - private static final Map abbreviations = new HashMap(7); - static { - for (DayOfWeek day : DayOfWeek.values()) { - abbreviations.put(day.getAbbr(), day); - } - } - private String dayName = null; private DayOfWeek dow; private boolean lastOne = false; @@ -166,13 +154,23 @@ String getDayOfWeekForSimpleTimeZone() { return sign + toString(d); } - private static DayOfWeek getDOW(String abbr) { - return abbreviations.get(abbr); + private static DayOfWeek getDOW(String name) { + int len = name.length(); + + if (name.regionMatches(true, 0, "Monday", 0, len)) return DayOfWeek.MONDAY; + if (name.regionMatches(true, 0, "Tuesday", 0, len)) return DayOfWeek.TUESDAY; + if (name.regionMatches(true, 0, "Wednesday", 0, len)) return DayOfWeek.WEDNESDAY; + if (name.regionMatches(true, 0, "Thursday", 0, len)) return DayOfWeek.THURSDAY; + if (name.regionMatches(true, 0, "Friday", 0, len)) return DayOfWeek.FRIDAY; + if (name.regionMatches(true, 0, "Saturday", 0, len)) return DayOfWeek.SATURDAY; + if (name.regionMatches(true, 0, "Sunday", 0, len)) return DayOfWeek.SUNDAY; + + throw new IllegalArgumentException("Unknown day-of-week: " + name); } /** * Converts the specified day of week value to the day-of-week - * name defined in {@link java.util.Calenda}. + * name defined in {@link java.util.Calendar}. * @param dow 1-based day of week value * @return the Calendar day of week name with "Calendar." prefix. * @throws IllegalArgumentException if the specified dow value is out of range. diff --git a/test/jdk/sun/util/calendar/zi/RuleRec.java b/test/jdk/sun/util/calendar/zi/RuleRec.java index 6d9d4905d6a..e6e18773d16 100644 --- a/test/jdk/sun/util/calendar/zi/RuleRec.java +++ b/test/jdk/sun/util/calendar/zi/RuleRec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -168,12 +168,13 @@ static RuleRec parse(StringTokenizer tokens) { rec.toYear = Integer.parseInt(token); } catch (NumberFormatException e) { // it's not integer - if ("min".equals(token) || "minimum".equals(token)) { + int len = token.length(); + if (token.regionMatches(true, 0, "minimum", 0, len)) { rec.fromYear = Zoneinfo.getMinYear(); - } else if ("max".equals(token) || "maximum".equals(token)) { + } else if (token.regionMatches(true, 0, "maximum", 0, len)) { rec.toYear = Integer.MAX_VALUE; rec.isLastRule = true; - } else if ("only".equals(token)) { + } else if (token.regionMatches(true, 0, "only", 0, len)) { rec.toYear = rec.fromYear; } else { Main.panic("invalid year value: "+token); diff --git a/test/jdk/sun/util/calendar/zi/Zoneinfo.java b/test/jdk/sun/util/calendar/zi/Zoneinfo.java index f395101d865..e125ad2cb87 100644 --- a/test/jdk/sun/util/calendar/zi/Zoneinfo.java +++ b/test/jdk/sun/util/calendar/zi/Zoneinfo.java @@ -240,8 +240,9 @@ static Zoneinfo parse(String fname) { continue; } String token = tokens.nextToken(); + int len = token.length(); - if (continued || "Zone".equals(token)) { + if (continued || token.regionMatches(true, 0, "Zone", 0, len)){ if (zone == null) { if (!tokens.hasMoreTokens()) { panic("syntax error: zone no more token"); @@ -268,7 +269,7 @@ static Zoneinfo parse(String fname) { } zone = null; } - } else if ("Rule".equals(token)) { + } else if (token.regionMatches(true, 0, "Rule", 0, len)) { if (!tokens.hasMoreTokens()) { panic("syntax error: rule no more token"); } @@ -281,7 +282,7 @@ static Zoneinfo parse(String fname) { RuleRec rrec = RuleRec.parse(tokens); rrec.setLine(line); rule.add(rrec); - } else if ("Link".equals(token)) { + } else if (token.regionMatches(true, 0, "Link", 0, len)) { // Link try { String name1 = tokens.nextToken(); diff --git a/test/jdk/tools/jimage/JImageToolTest.java b/test/jdk/tools/jimage/JImageToolTest.java index feb6a56a968..b1006c89679 100644 --- a/test/jdk/tools/jimage/JImageToolTest.java +++ b/test/jdk/tools/jimage/JImageToolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -42,7 +42,7 @@ public class JImageToolTest { private static void jimage(String... jimageArgs) throws Exception { ArrayList args = new ArrayList<>(); - args.add("-ms64m"); + args.add("-Xms64m"); args.add("jdk.tools.jimage.Main"); args.addAll(Arrays.asList(jimageArgs)); diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 49cc6e14311..795a658afa5 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -133,6 +133,7 @@ public Map call() { map.put("vm.compiler1.enabled", this::isCompiler1Enabled); map.put("vm.compiler2.enabled", this::isCompiler2Enabled); map.put("docker.support", this::dockerSupport); + map.put("systemd.support", this::systemdSupport); map.put("vm.musl", this::isMusl); map.put("release.implementor", this::implementor); map.put("jdk.containerized", this::jdkContainerized); @@ -610,7 +611,7 @@ protected String dockerSupport() { if (isSupported) { try { - isSupported = checkDockerSupport(); + isSupported = checkProgramSupport("checkDockerSupport()", Container.ENGINE_COMMAND); } catch (Exception e) { isSupported = false; } @@ -620,6 +621,27 @@ protected String dockerSupport() { return "" + isSupported; } + /** + * A simple check for systemd support + * + * @return true if systemd is supported in a given environment + */ + protected String systemdSupport() { + log("Entering systemdSupport()"); + + boolean isSupported = Platform.isLinux(); + if (isSupported) { + try { + isSupported = checkProgramSupport("checkSystemdSupport()", "systemd-run"); + } catch (Exception e) { + isSupported = false; + } + } + + log("systemdSupport(): returning isSupported = " + isSupported); + return "" + isSupported; + } + // Configures process builder to redirect process stdout and stderr to a file. // Returns file names for stdout and stderr. private Map redirectOutputToLogFile(String msg, ProcessBuilder pb, String fileNameBase) { @@ -654,17 +676,17 @@ private void printLogfileContent(Map logFileNames) { }); } - private boolean checkDockerSupport() throws IOException, InterruptedException { - log("checkDockerSupport(): entering"); - ProcessBuilder pb = new ProcessBuilder("which", Container.ENGINE_COMMAND); + private boolean checkProgramSupport(String logString, String cmd) throws IOException, InterruptedException { + log(logString + ": entering"); + ProcessBuilder pb = new ProcessBuilder("which", cmd); Map logFileNames = - redirectOutputToLogFile("checkDockerSupport(): which " + Container.ENGINE_COMMAND, - pb, "which-container"); + redirectOutputToLogFile(logString + ": which " + cmd, + pb, "which-cmd"); Process p = pb.start(); p.waitFor(10, TimeUnit.SECONDS); int exitValue = p.exitValue(); - log(String.format("checkDockerSupport(): exitValue = %s, pid = %s", exitValue, p.pid())); + log(String.format("%s: exitValue = %s, pid = %s", logString, exitValue, p.pid())); if (exitValue != 0) { printLogfileContent(logFileNames); } diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index 28926af0254..6ac84faaf7d 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -61,7 +61,6 @@ tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java 8057687 generic-all emit correct byte code an attributes for type annotations tools/javac/warnings/suppress/TypeAnnotations.java 8057683 generic-all improve ordering of errors with type annotations tools/javac/modules/SourceInSymlinkTest.java 8180263 windows-all fails when run on a subst drive -tools/javac/patterns/Exhaustiveness.java 8326616 generic-all intermittently timeout ########################################################################### # diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java index 9a9b20541c8..03adf00ca73 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java @@ -70,19 +70,19 @@ public void test() { // Generate the HTML output using the HTML document generation within doclet. public static String generateHtmlTree() { // Document type for the HTML document - HtmlTree html = new HtmlTree(HtmlTag.HTML); - HtmlTree head = new HtmlTree(HtmlTag.HEAD); - HtmlTree title = new HtmlTree(HtmlTag.TITLE); + HtmlTree html = HtmlTree.of(HtmlTag.HTML); + HtmlTree head = HtmlTree.of(HtmlTag.HEAD); + HtmlTree title = HtmlTree.of(HtmlTag.TITLE); // String content within the document TextBuilder titleContent = new TextBuilder("Markup test"); title.add(titleContent); head.add(title); // Test META tag - HtmlTree meta = new HtmlTree(HtmlTag.META); + HtmlTree meta = HtmlTree.of(HtmlTag.META); meta.put(HtmlAttr.NAME, "keywords"); meta.put(HtmlAttr.CONTENT, "testContent"); head.add(meta); - HtmlTree link = new HtmlTree(HtmlTag.LINK); + HtmlTree link = HtmlTree.of(HtmlTag.LINK); link.put(HtmlAttr.REL, "testRel"); link.put(HtmlAttr.HREF, "testLink.html"); head.add(link); @@ -90,10 +90,10 @@ public static String generateHtmlTree() { // Comment within the document Comment bodyMarker = new Comment("======== START OF BODY ========"); html.add(bodyMarker); - HtmlTree body = new HtmlTree(HtmlTag.BODY); + HtmlTree body = HtmlTree.of(HtmlTag.BODY); Comment pMarker = new Comment("======== START OF PARAGRAPH ========"); body.add(pMarker); - HtmlTree p = new HtmlTree(HtmlTag.P); + HtmlTree p = HtmlTree.of(HtmlTag.P); TextBuilder bodyContent = new TextBuilder( "This document is generated from sample source code and HTML " + "files with examples of a wide variety of Java language constructs: packages, " + @@ -106,24 +106,24 @@ public static String generateHtmlTree() { TextBuilder pContent = new TextBuilder(" to out a link."); p.add(pContent); body.add(p); - HtmlTree p1 = new HtmlTree(HtmlTag.P); + HtmlTree p1 = HtmlTree.of(HtmlTag.P); // Test another version of A tag. - HtmlTree anchor = new HtmlTree(HtmlTag.A); + HtmlTree anchor = HtmlTree.of(HtmlTag.A); anchor.put(HtmlAttr.HREF, "testLink.html"); anchor.put(HtmlAttr.ID, "Another version of a tag"); p1.add(anchor); body.add(p1); // Test for empty tags. - HtmlTree dl = new HtmlTree(HtmlTag.DL); + HtmlTree dl = HtmlTree.of(HtmlTag.DL); html.add(dl); // Test for empty nested tags. - HtmlTree dlTree = new HtmlTree(HtmlTag.DL); - dlTree.add(new HtmlTree(HtmlTag.DT)); - dlTree.add(new HtmlTree (HtmlTag.DD)); + HtmlTree dlTree = HtmlTree.of(HtmlTag.DL); + dlTree.add(HtmlTree.of(HtmlTag.DT)); + dlTree.add(HtmlTree.of (HtmlTag.DD)); html.add(dlTree); - HtmlTree dlDisplay = new HtmlTree(HtmlTag.DL); - dlDisplay.add(new HtmlTree(HtmlTag.DT)); - HtmlTree dd = new HtmlTree (HtmlTag.DD); + HtmlTree dlDisplay = HtmlTree.of(HtmlTag.DL); + dlDisplay.add(HtmlTree.of(HtmlTag.DT)); + HtmlTree dd = HtmlTree.of (HtmlTag.DD); TextBuilder ddContent = new TextBuilder("Test DD"); dd.add(ddContent); dlDisplay.add(dd); @@ -132,7 +132,7 @@ public static String generateHtmlTree() { body.add(emptyString); Comment emptyComment = new Comment(""); body.add(emptyComment); - HtmlTree hr = new HtmlTree(HtmlTag.HR); + HtmlTree hr = HtmlTree.of(HtmlTag.HR); body.add(hr); html.add(body); HtmlDocument htmlDoc = new HtmlDocument(html); diff --git a/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java b/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java index bd44fe88141..518ecebd704 100644 --- a/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java +++ b/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java @@ -55,7 +55,7 @@ public static void main(String[] args) { } private static void check(HtmlTag htmlTag) { - boolean elementIsVoid = new HtmlTree(htmlTag).isVoid(); + boolean elementIsVoid = HtmlTree.of(htmlTag).isVoid(); boolean elementHasNoEndTag = htmlTag.endKind == HtmlTag.EndKind.NONE; if (elementIsVoid != elementHasNoEndTag) { throw new AssertionError(htmlTag + ", " + elementIsVoid + ", " + elementHasNoEndTag); diff --git a/test/langtools/jdk/jshell/ExceptionMessageTest.java b/test/langtools/jdk/jshell/ExceptionMessageTest.java index 9f8b53f1563..fe8eec57739 100644 --- a/test/langtools/jdk/jshell/ExceptionMessageTest.java +++ b/test/langtools/jdk/jshell/ExceptionMessageTest.java @@ -26,6 +26,7 @@ * @bug 8185108 * @summary Test exception().getMessage() in events returned by eval() * @run testng ExceptionMessageTest + * @key intermittent */ import java.util.HashMap; diff --git a/test/langtools/tools/javac/T6435291/T.jcod b/test/langtools/tools/javac/T6435291/T.jcod deleted file mode 100644 index 9175f4f4041..00000000000 --- a/test/langtools/tools/javac/T6435291/T.jcod +++ /dev/null @@ -1,320 +0,0 @@ -class T { - 0xCAFEBABE; - 0; // minor version - 49; // version - [73] { // Constant Pool - ; // first element is empty - Utf8 "T"; // #1 at 0x0A - class #1; // #2 at 0x1A - Utf8 "Ljava/lang/Enum;"; // #3 at 0x1D - Utf8 "java/lang/Enum"; // #4 at 0x41 - class #4; // #5 at 0x52 - Utf8 "T.java"; // #6 at 0x55 - Utf8 "T1"; // #7 at 0x61 - Utf8 "LT;"; // #8 at 0x66 - Utf8 "T2"; // #9 at 0x78 - Utf8 "T3"; // #10 at 0x7D - Utf8 "myName"; // #11 at 0x82 - Utf8 "Ljava/lang/String;"; // #12 at 0x8B - Utf8 "$VALUES"; // #13 at 0xA0 - Utf8 "[LT;"; // #14 at 0xAA - Utf8 "values"; // #15 at 0xBD - Utf8 "()[LT;"; // #16 at 0xC6 - NameAndType #13 #14; // #17 at 0xDB - Field #2 #17; // #18 at 0xE0 - class #14; // #19 at 0xE5 - Utf8 "clone"; // #20 at 0xE8 - Utf8 "()Ljava/lang/Object;"; // #21 at 0xF0 - NameAndType #20 #21; // #22 at 0x0107 - Method #19 #22; // #23 at 0x010C - Utf8 "valueOf"; // #24 at 0x0111 - Utf8 "(Ljava/lang/String;)LT;"; // #25 at 0x011B - Utf8 "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;"; // #26 at 0x0141 - NameAndType #24 #26; // #27 at 0x0179 - Method #5 #27; // #28 at 0x017E - Utf8 "name"; // #29 at 0x0183 - Utf8 "getName"; // #30 at 0x018A - Utf8 "()Ljava/lang/String;"; // #31 at 0x0194 - NameAndType #11 #12; // #32 at 0x01AB - Field #2 #32; // #33 at 0x01B0 - Utf8 "this"; // #34 at 0x01B5 - Utf8 ""; // #35 at 0x01BC - Utf8 "(Ljava/lang/String;ILjava/lang/String;)V"; // #36 at 0x01C5 - Utf8 "LNotNull;"; // #37 at 0x01F0 - Utf8 "java/lang/IllegalArgumentException"; // #38 at 0x0216 - class #38; // #39 at 0x023B - Utf8 "Argument 0 for @NotNull parameter of T. must not be null"; // #40 at 0x023E - String #40; // #41 at 0x028B - Utf8 "(Ljava/lang/String;)V"; // #42 at 0x028E - NameAndType #35 #42; // #43 at 0x02A6 - Method #39 #43; // #44 at 0x02AB - Utf8 "(Ljava/lang/String;I)V"; // #45 at 0x02B0 - NameAndType #35 #45; // #46 at 0x02C9 - Method #5 #46; // #47 at 0x02CE - Utf8 ""; // #48 at 0x02D3 - Utf8 "()V"; // #49 at 0x02DE - String #7; // #50 at 0x02E4 - Utf8 "type1"; // #51 at 0x02E7 - String #51; // #52 at 0x02EF - NameAndType #35 #36; // #53 at 0x02F2 - Method #2 #53; // #54 at 0x02F7 - NameAndType #7 #8; // #55 at 0x02FC - Field #2 #55; // #56 at 0x0301 - String #9; // #57 at 0x0306 - Utf8 "type2"; // #58 at 0x0309 - String #58; // #59 at 0x0311 - NameAndType #9 #8; // #60 at 0x0314 - Field #2 #60; // #61 at 0x0319 - String #10; // #62 at 0x031E - Utf8 "type3"; // #63 at 0x0321 - String #63; // #64 at 0x0329 - NameAndType #10 #8; // #65 at 0x032C - Field #2 #65; // #66 at 0x0331 - Utf8 "Code"; // #67 at 0x0336 - Utf8 "LineNumberTable"; // #68 at 0x033D - Utf8 "LocalVariableTable"; // #69 at 0x034F - Utf8 "Signature"; // #70 at 0x0364 - Utf8 "RuntimeInvisibleParameterAnnotations"; // #71 at 0x0370 - Utf8 "SourceFile"; // #72 at 0x0397 - } // Constant Pool - - 0x4031; // access - #2;// this_cpx - #5;// super_cpx - - [0] { // Interfaces - } // Interfaces - - [5] { // fields - { // Member at 0x03AE - 0x4019; // access - #7; // name_cpx - #8; // sig_cpx - [0] { // Attributes - } // Attributes - } // Member - ; - { // Member at 0x03B6 - 0x4019; // access - #9; // name_cpx - #8; // sig_cpx - [0] { // Attributes - } // Attributes - } // Member - ; - { // Member at 0x03BE - 0x4019; // access - #10; // name_cpx - #8; // sig_cpx - [0] { // Attributes - } // Attributes - } // Member - ; - { // Member at 0x03C6 - 0x0012; // access - #11; // name_cpx - #12; // sig_cpx - [0] { // Attributes - } // Attributes - } // Member - ; - { // Member at 0x03CE - 0x101A; // access - #13; // name_cpx - #14; // sig_cpx - [0] { // Attributes - } // Attributes - } // Member - } // fields - - [5] { // methods - { // Member at 0x03D8 - 0x0019; // access - #15; // name_cpx - #16; // sig_cpx - [1] { // Attributes - Attr(#67, 34) { // Code at 0x03E0 - 1; // max_stack - 0; // max_locals - Bytes[10]{ - 0xB20012B60017C000; - 0x13B0; - }; - [0] { // Traps - } // end Traps - [1] { // Attributes - Attr(#68, 6) { // LineNumberTable at 0x03FC - [1] { // LineNumberTable - 0 9; // at 0x0408 - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x0408 - 0x0009; // access - #24; // name_cpx - #25; // sig_cpx - [1] { // Attributes - Attr(#67, 52) { // Code at 0x0410 - 2; // max_stack - 1; // max_locals - Bytes[10]{ - 0x12022AB8001CC000; - 0x02B0; - }; - [0] { // Traps - } // end Traps - [2] { // Attributes - Attr(#69, 12) { // LocalVariableTable at 0x042C - [1] { // LocalVariableTable - 0 10 29 12 0; // at 0x043E - } - } // end LocalVariableTable - ; - Attr(#68, 6) { // LineNumberTable at 0x043E - [1] { // LineNumberTable - 0 9; // at 0x044A - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x044A - 0x0001; // access - #30; // name_cpx - #31; // sig_cpx - [1] { // Attributes - Attr(#67, 47) { // Code at 0x0452 - 1; // max_stack - 1; // max_locals - Bytes[5]{ - 0x2AB40021B0; - }; - [0] { // Traps - } // end Traps - [2] { // Attributes - Attr(#69, 12) { // LocalVariableTable at 0x0469 - [1] { // LocalVariableTable - 0 5 34 8 0; // at 0x047B - } - } // end LocalVariableTable - ; - Attr(#68, 6) { // LineNumberTable at 0x047B - [1] { // LineNumberTable - 0 17; // at 0x0487 - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x0487 - 0x0002; // access - #35; // name_cpx - #36; // sig_cpx - [3] { // Attributes - Attr(#67, 86) { // Code at 0x048F - 3; // max_stack - 4; // max_locals - Bytes[26]{ - 0x2BC7000DBB002759; - 0x1229B7002CBF2A2B; - 0x1CB7002F2A2DB500; - 0x21B1; - }; - [0] { // Traps - } // end Traps - [2] { // Attributes - Attr(#69, 22) { // LocalVariableTable at 0x04BB - [2] { // LocalVariableTable - 14 12 34 8 0; // at 0x04CD - 14 12 29 12 3; // at 0x04D7 - } - } // end LocalVariableTable - ; - Attr(#68, 14) { // LineNumberTable at 0x04D7 - [3] { // LineNumberTable - 14 20; // at 0x04E3 - 20 21; // at 0x04E7 - 25 22; // at 0x04EB - } - } // end LineNumberTable - } // Attributes - } // end Code - ; - Attr(#70, 2) { // Signature at 0x04EB - #42; - } // end Signature - ; - Attr(#71, 11) { // RuntimeInvisibleParameterAnnotations at 0x04F3 - [3]b { // parameters - [1] { // annotations - { // annotation - #37; - [0] { // element_value_pairs - } // element_value_pairs - } // annotation - } - ; - [0] { // annotations - } - ; - [0] { // annotations - } - } - } // end RuntimeInvisibleParameterAnnotations - } // Attributes - } // Member - ; - { // Member at 0x0504 - 0x0008; // access - #48; // name_cpx - #49; // sig_cpx - [1] { // Attributes - Attr(#67, 107) { // Code at 0x050C - 5; // max_stack - 0; // max_locals - Bytes[71]{ - 0xBB00025912320312; - 0x34B70036B30038BB; - 0x000259123904123B; - 0xB70036B3003DBB00; - 0x0259123E051240B7; - 0x0036B3004206BD00; - 0x025903B200385359; - 0x04B2003D535905B2; - 0x004253B30012B1; - }; - [0] { // Traps - } // end Traps - [1] { // Attributes - Attr(#68, 18) { // LineNumberTable at 0x0565 - [4] { // LineNumberTable - 0 10; // at 0x0571 - 15 11; // at 0x0575 - 30 12; // at 0x0579 - 45 9; // at 0x057D - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - } // methods - - [2] { // Attributes - Attr(#70, 2) { // Signature at 0x057F - #3; - } // end Signature - ; - Attr(#72, 2) { // SourceFile at 0x0587 - #6; - } // end SourceFile - } // Attributes -} // end class T diff --git a/test/langtools/tools/javac/T6435291/T6435291.java b/test/langtools/tools/javac/T6435291/T6435291.java deleted file mode 100644 index 33c6038b697..00000000000 --- a/test/langtools/tools/javac/T6435291/T6435291.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 6435291 - * @summary javac shouldn't throw NPE while compiling invalid RuntimeInvisibleParameterAnnotations - * @author Wei Tao - * @modules jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.code - * jdk.compiler/com.sun.tools.javac.comp - * jdk.compiler/com.sun.tools.javac.main - * jdk.compiler/com.sun.tools.javac.util - * @build T - * @run main/othervm T6435291 - */ - -import com.sun.tools.javac.api.JavacTaskImpl; -import com.sun.tools.javac.code.ClassFinder.BadClassFile; -import com.sun.tools.javac.code.Symtab; -import com.sun.tools.javac.util.Names; -import javax.tools.ToolProvider; - -public class T6435291 { - public static void main(String... args) { - javax.tools.JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - JavacTaskImpl task = (JavacTaskImpl)tool.getTask(null, null, null, null, null, null); - Symtab syms = Symtab.instance(task.getContext()); - Names names = Names.instance(task.getContext()); - task.ensureEntered(); - try { - syms.enterClass(syms.unnamedModule, names.fromString("T")).complete(); - } catch (BadClassFile e) { - System.err.println("Passed: expected completion failure " + e.getClass().getName()); - return; - } catch (Exception e) { - throw new RuntimeException("Failed: unexpected exception"); - } - throw new RuntimeException("Failed: no error reported"); - } -} diff --git a/test/langtools/tools/javac/annotations/parameter/ParameterAnnotations.java b/test/langtools/tools/javac/annotations/parameter/ParameterAnnotations.java new file mode 100644 index 00000000000..395765fcb80 --- /dev/null +++ b/test/langtools/tools/javac/annotations/parameter/ParameterAnnotations.java @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2024, 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 8024694 8334870 + * @summary Check javac can handle various Runtime(In)VisibleParameterAnnotations attribute combinations + * @enablePreview + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main ParameterAnnotations +*/ + +import java.io.OutputStream; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.MethodBuilder; +import java.lang.classfile.MethodElement; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.attribute.MethodParametersAttribute; +import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; +import java.lang.classfile.attribute.SignatureAttribute; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.ElementFilter; + +import toolbox.TestRunner; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class ParameterAnnotations extends TestRunner { + + ToolBox tb; + + public static void main(String... args) throws Exception { + new ParameterAnnotations().runTests(); + } + + ParameterAnnotations() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testEnum(Path base) throws Exception { + //not parameterized: + doTest(base, + """ + import java.lang.annotation.*; + public enum E { + A(0); + E(@Visible @Invisible long i) {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "E", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + //parameterized: + doTest(base, + """ + import java.lang.annotation.*; + public enum E { + A(0); + E(@Visible @Invisible long i) {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "E", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + //not parameterized, and no Signature attribute: + doTest(base, + """ + import java.lang.annotation.*; + public enum E { + A(0); + E(@Visible @Invisible long i) {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "E", + NO_SIGNATURE, + "java.lang.String, int, @Invisible @Visible long"); + //not parameterized, and no Signature and MethodParameters attribute: + doTest(base, + """ + import java.lang.annotation.*; + public enum E { + A(0); + E(@Visible @Invisible long i) {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "E", + NO_SIGNATURE_NO_METHOD_PARAMETERS, + "java.lang.String, int, @Invisible @Visible long"); + } + + @Test + public void testInnerClass(Path base) throws Exception { + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString(); //force outer this capture + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$I", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString(); //force outer this capture + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$I", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString(); //force outer this capture + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$I", + NO_SIGNATURE, + "@Invisible @Visible long"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString(); //force outer this capture + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$I", + NO_SIGNATURE_NO_METHOD_PARAMETERS, + "@Invisible @Visible long"); + } + + @Test + public void testCapturingLocal(Path base) throws Exception { + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public void test(int i) { + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public void test(int i) { + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public void test(int i) { + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + NO_SIGNATURE, + "T, @Invisible @Visible long, int"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public void test(int i) { + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + NO_SIGNATURE_NO_METHOD_PARAMETERS, + "T, @Invisible @Visible long, int"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + { + int i = 0; + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + { + int i = 0; + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + MethodTransform.ACCEPT_ALL, + "@Invisible @Visible long"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + { + int i = 0; + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + NO_SIGNATURE, + "T, @Invisible @Visible long, int"); + doTest(base, + """ + import java.lang.annotation.*; + public class T { + { + int i = 0; + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + NO_SIGNATURE_NO_METHOD_PARAMETERS, + "T, @Invisible @Visible long, int"); + } + + @Test + public void testSyntheticTests(Path base) throws Exception { + //Signature attribute will defined one parameter, but the + //Runtime(In)VisibleParameterAnnotations will define 3 parameters: + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public void test(int i) { + class I { + public I(@Visible @Invisible long l) {} + public String toString() { + return T.this.toString() + i; //force outer this capture + } + } + } + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T$1I", + new MethodTransform() { + @Override + public void accept(MethodBuilder builder, MethodElement element) { + if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 1; + builder.accept(RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of()))); + } else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 1; + builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of()))); + } else { + builder.accept(element); + } + } + }, + "@Invisible @Visible long"); + //no Signature attribute, no synthetic parameters, + //but less entries in Runtime(In)VisibleParameterAnnotations than parameters + //no way to map anything: + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public T(int i, @Visible @Invisible long l, String s) {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T", + new MethodTransform() { + @Override + public void accept(MethodBuilder builder, MethodElement element) { + if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 3; + builder.accept(RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(annos.parameterAnnotations().get(1)))); + } else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 3; + builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(annos.parameterAnnotations().get(1)))); + } else { + builder.accept(element); + } + } + }, + "int, long, java.lang.String", + "- compiler.warn.runtime.invisible.parameter.annotations: T.class", + "1 warning"); + //no Signature attribute, no synthetic parameters, + //but more entries in Runtime(In)VisibleParameterAnnotations than parameters + //no way to map anything: + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public T(@Visible @Invisible long l) {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T", + new MethodTransform() { + @Override + public void accept(MethodBuilder builder, MethodElement element) { + if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 1; + builder.accept(RuntimeInvisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of()))); + } else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 1; + builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of()))); + } else { + builder.accept(element); + } + } + }, + "long", + "- compiler.warn.runtime.invisible.parameter.annotations: T.class", + "1 warning"); + //mismatched lengths on RuntimeVisibleParameterAnnotations and + //RuntimeInvisibleParameterAnnotations: + doTest(base, + """ + import java.lang.annotation.*; + public class T { + public T(@Visible @Invisible long l) {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "T", + new MethodTransform() { + @Override + public void accept(MethodBuilder builder, MethodElement element) { + if (element instanceof RuntimeInvisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 1; + builder.accept(annos); //keep intact + } else if (element instanceof RuntimeVisibleParameterAnnotationsAttribute annos) { + assert annos.parameterAnnotations().size() == 1; + builder.accept(RuntimeVisibleParameterAnnotationsAttribute.of(List.of(List.of(), annos.parameterAnnotations().get(0), List.of()))); + } else { + builder.accept(element); + } + } + }, + "long", + "- compiler.warn.runtime.visible.invisible.param.annotations.mismatch: T.class", + "1 warning"); + } + + @Test + public void testRecord(Path base) throws Exception { + //implicit constructor: + doTest(base, + """ + import java.lang.annotation.*; + public record R(int i, @Visible @Invisible long l, String s) { + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "R", + MethodTransform.ACCEPT_ALL, + "int, @Invisible @Visible long, java.lang.String"); + doTest(base, + """ + import java.lang.annotation.*; + public record R(int i, @Visible @Invisible long l, String s) { + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "R", + NO_SIGNATURE, + "int, @Invisible @Visible long, java.lang.String"); + doTest(base, + """ + import java.lang.annotation.*; + public record R(int i, @Visible @Invisible long l, String s) { + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "R", + NO_SIGNATURE_NO_METHOD_PARAMETERS, + "int, @Invisible @Visible long, java.lang.String"); + //compact constructor: + doTest(base, + """ + import java.lang.annotation.*; + public record R(int i, @Visible @Invisible long l, String s) { + public R {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "R", + MethodTransform.ACCEPT_ALL, + "int, @Invisible @Visible long, java.lang.String"); + doTest(base, + """ + import java.lang.annotation.*; + public record R(int i, @Visible @Invisible long l, String s) { + public R {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "R", + NO_SIGNATURE, + "int, @Invisible @Visible long, java.lang.String"); + doTest(base, + """ + import java.lang.annotation.*; + public record R(int i, @Visible @Invisible long l, String s) { + public R {} + } + @Retention(RetentionPolicy.RUNTIME) + @interface Visible {} + @interface Invisible {} + """, + "R", + NO_SIGNATURE_NO_METHOD_PARAMETERS, + "int, @Invisible @Visible long, java.lang.String"); + } + + private MethodTransform NO_SIGNATURE = + MethodTransform.dropping(element -> element instanceof SignatureAttribute); + + private MethodTransform NO_SIGNATURE_NO_METHOD_PARAMETERS = + MethodTransform.dropping(element -> element instanceof SignatureAttribute || + element instanceof MethodParametersAttribute); + + private void doTest(Path base, String code, String binaryNameToCheck, + MethodTransform changeConstructor, String expectedOutput, + String... expectedDiagnostics) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, code); + + Files.createDirectories(classes); + + new JavacTask(tb) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + Path classfile = classes.resolve(binaryNameToCheck + ".class"); + ClassFile cf = ClassFile.of(); + + ClassModel model = cf.parse(classfile); + + byte[] newClassFile = cf.transformClass(model, + ClassTransform.transformingMethods(m -> m.methodName() + .equalsString(""), + changeConstructor)); + + try (OutputStream out = Files.newOutputStream(classfile)) { + out.write(newClassFile); + } + + Task.Result result = new JavacTask(tb) + .options("-classpath", classes.toString(), + "-processor", TestAP.class.getName(), + "-XDrawDiagnostics", + "-Xlint:classfile") + .outdir(classes) + .classes(binaryNameToCheck) + .run(Task.Expect.SUCCESS) + .writeAll(); + List out = result.getOutputLines(Task.OutputKind.STDOUT); + if (!out.equals(List.of(expectedOutput))) { + throw new AssertionError("Expected: " + List.of(expectedOutput) + ", but got: " + out); + } + List diagnostics = + new ArrayList<>(result.getOutputLines(Task.OutputKind.DIRECT)); + diagnostics.remove(""); + if (!diagnostics.equals(List.of(expectedDiagnostics))) { + throw new AssertionError("Expected: " + List.of(expectedDiagnostics) + ", but got: " + diagnostics); + } + } + + @SupportedAnnotationTypes("*") + public static final class TestAP extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (TypeElement clazz : ElementFilter.typesIn(roundEnv.getRootElements())) { + for (ExecutableElement el : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { + String sep = ""; + + for (VariableElement p : el.getParameters()) { + System.out.print(sep); + if (!p.getAnnotationMirrors().isEmpty()) { + System.out.print(p.getAnnotationMirrors() + .stream() + .map(m -> m.toString()) + .collect(Collectors.joining(" "))); + System.out.print(" "); + } + System.out.print(p.asType()); + sep = ", "; + } + + System.out.println(); + } + } + + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + } +} diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index b2603338509..329e716a780 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -55,7 +55,8 @@ compiler.misc.bad.constant.range # bad class file compiler.misc.bad.constant.value # bad class file compiler.misc.bad.enclosing.class # bad class file compiler.misc.bad.enclosing.method # bad class file -compiler.misc.bad.runtime.invisible.param.annotations # bad class file +compiler.warn.runtime.invisible.parameter.annotations # bad class file +compiler.warn.runtime.visible.invisible.param.annotations.mismatch # bad class file compiler.misc.bad.signature # bad class file compiler.misc.bad.requires.flag # bad class file compiler.misc.bad.utf8.byte.sequence.at # bad class file diff --git a/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java b/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java new file mode 100644 index 00000000000..5f5d513a8b2 --- /dev/null +++ b/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.containers.systemd; + +import static jdk.test.lib.Asserts.assertNotNull; + +import java.util.ArrayList; +import java.util.Collections; + + +// This class represents options for running java inside systemd slices +// in test environment. +public class SystemdRunOptions { + public ArrayList javaOpts = new ArrayList<>(); + public String classToRun; // class or "-version" + public ArrayList classParams = new ArrayList<>(); + public String memoryLimit; // used in slice for MemoryLimit property + public String cpuLimit; // used in slice for CPUQuota property + public String sliceName; // name of the slice (nests CPU in memory) + public String sliceDMemoryLimit; // used in jdk_internal.slice.d + public String sliceDCpuLimit; // used in jdk_internal.slice.d + + /** + * Convenience constructor for most common use cases in testing. + * @param classToRun a class to run, or "-version" + * @param javaOpts java options to use + * + * @return Default docker run options + */ + public SystemdRunOptions(String classToRun, String... javaOpts) { + this.classToRun = classToRun; + Collections.addAll(this.javaOpts, javaOpts); + this.sliceName = defaultSliceName(); + } + + private static String defaultSliceName() { + // Create a unique name for a systemd slice + // jtreg guarantees that test.name is unique among all concurrently executing + // tests. For example, if you have two test roots: + // + // $ find test -type f + // test/foo/TEST.ROOT + // test/foo/my/TestCase.java + // test/bar/TEST.ROOT + // test/bar/my/TestCase.java + // $ jtreg -concur:2 test/foo test/bar + // + // jtreg will first run all the tests under test/foo. When they are all finished, then + // jtreg will run all the tests under test/bar. So you will never have two concurrent + // test cases whose test.name is "my/TestCase.java" + String testname = System.getProperty("test.name"); + assertNotNull(testname, "must be set by jtreg"); + testname = testname.replace(".java", ""); + testname = testname.replace("/", "_"); + testname = testname.replace("\\", "_"); + testname = testname.replace("-", "_"); + + // Example: + // Memory: "test_containers_systemd_TestMemoryAwareness" + // CPU: "test_containers_systemd_TestMemoryAwareness-cpu" => derived + return testname; + } + + /** + * The memory limit set with a .slice file in the systemd + * config directory. + * + * @param memLimit The memory limit to set (e.g. 1000M). + * @return The run options. + */ + public SystemdRunOptions memoryLimit(String memLimit) { + this.memoryLimit = memLimit; + return this; + } + + /** + * The memory limit to set in the top-level jdk_internal.slice.d + * systemd config directory. + * + * @param memoryLimit The memory limit to set. + * @return The run options. + */ + public SystemdRunOptions sliceDMemoryLimit(String memoryLimit) { + this.sliceDMemoryLimit = memoryLimit; + return this; + } + + /** + * The CPU limit set with a .slice file in the systemd + * config directory. + * + * @param cpuLimit + * @return The run options. + */ + public SystemdRunOptions cpuLimit(String cpuLimit) { + this.cpuLimit = cpuLimit; + return this; + } + + /** + * The Cpu limit set in the top-level jdk_internal.slice.d + * systemd config directory. + * + * @param cpuLimit The CPU limit to set to. + * @return The run options. + */ + public SystemdRunOptions sliceDCpuLimit(String cpuLimit) { + this.sliceDCpuLimit = cpuLimit; + return this; + } + + public SystemdRunOptions sliceName(String name) { + this.sliceName = name; + return this; + } + + public SystemdRunOptions addJavaOpts(String... opts) { + Collections.addAll(javaOpts, opts); + return this; + } + + public SystemdRunOptions addClassOptions(String... opts) { + Collections.addAll(classParams,opts); + return this; + } + + public boolean hasSliceDLimit() { + return this.sliceDMemoryLimit != null || + this.sliceDCpuLimit != null; + } +} diff --git a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java new file mode 100644 index 00000000000..341b24c3e05 --- /dev/null +++ b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.containers.systemd; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import jdk.internal.platform.Metrics; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.FileUtils; +import jtreg.SkippedException; + +public class SystemdTestUtils { + + private static final String CGROUPS_PROVIDER = Metrics.systemMetrics().getProvider(); + private static boolean CGROUPS_V2 = "cgroupv2".equals(CGROUPS_PROVIDER); + public static boolean RUN_AS_USER = !Platform.isRoot() && CGROUPS_V2; + private static final String SLICE_NAMESPACE_PREFIX = "jdk_internal"; + private static final String SLICE_D_MEM_CONFIG_FILE = "memory-limit.conf"; + private static final String SLICE_D_CPU_CONFIG_FILE = "cpu-limit.conf"; + private static final String USER_HOME = System.getProperty("user.home"); + private static final Path SYSTEMD_CONFIG_HOME_ROOT = Path.of("/", "etc", "systemd", "system"); + private static final Path SYSTEMD_CONFIG_HOME_USER = Path.of(USER_HOME, ".config", "systemd", "user"); + private static final Path SYSTEMD_CONFIG_HOME = Platform.isRoot() ? SYSTEMD_CONFIG_HOME_ROOT : SYSTEMD_CONFIG_HOME_USER; + + // Specifies how many lines to copy from child STDOUT to main test output. + // Having too many lines in the main test output will result + // in JT harness trimming the output, and can lead to loss of useful + // diagnostic information. + private static final int MAX_LINES_TO_COPY_FOR_CHILD_STDOUT = 100; + + public record ResultFiles(Path memory, Path cpu, Path sliceDotDDir) {} + + /** + * Create commonly used options with the class to be launched inside the + * systemd slice + * + * @param testClass The test class or {@code -version} + * @return The basic options. + */ + public static SystemdRunOptions newOpts(String testClass) { + return new SystemdRunOptions(testClass, + "-Xlog:os+container=trace", + "-cp", + Utils.TEST_CLASSES); + } + + /** + * Run Java inside a systemd slice with specified parameters and options. + * + * @param opts The systemd slice options when running java + * @return An OutputAnalyzer of the output of the command than ran. + * @throws Exception If something went wrong. + * @throws SkippedException If the test cannot be run (i.e. non-root user + * on cgroups v1). + */ + public static OutputAnalyzer buildAndRunSystemdJava(SystemdRunOptions opts) throws Exception, SkippedException { + if (!Platform.isRoot() && !CGROUPS_V2) { + throw new SkippedException("Systemd tests require root on cgroup v1. Test skipped!"); + } + ResultFiles files = SystemdTestUtils.buildSystemdSlices(opts); + + try { + return SystemdTestUtils.systemdRunJava(opts); + } finally { + try { + if (files.memory() != null) { + Files.delete(files.memory()); + } + if (files.cpu() != null) { + Files.delete(files.cpu()); + } + if (files.sliceDotDDir() != null) { + FileUtils.deleteFileTreeUnchecked(files.sliceDotDDir()); + } + } catch (NoSuchFileException e) { + // ignore + } + } + } + + private static OutputAnalyzer systemdRunJava(SystemdRunOptions opts) throws Exception { + return execute(buildJavaCommand(opts)); + } + + /** + * Create systemd slice files under /etc/systemd/system. + * + * The JDK will then run within that slice as provided by the SystemdRunOptions. + * + * @param runOpts The systemd slice options to use when running the test. + * @return The systemd slice files (for cleanup-purposes later). + * @throws Exception + */ + private static ResultFiles buildSystemdSlices(SystemdRunOptions runOpts) throws Exception { + String sliceName = sliceName(runOpts); + String sliceNameCpu = sliceNameCpu(runOpts); + + // Generate systemd slices for cpu/memory + String memorySliceContent = getMemorySlice(runOpts, sliceName); + String cpuSliceContent = getCpuSlice(runOpts, sliceName); + + // Ensure base directory exists + Files.createDirectories(SYSTEMD_CONFIG_HOME); + Path sliceDotDDir = null; + if (runOpts.hasSliceDLimit()) { + String dirName = String.format("%s.slice.d", SLICE_NAMESPACE_PREFIX); + sliceDotDDir = SYSTEMD_CONFIG_HOME.resolve(Path.of(dirName)); + Files.createDirectory(sliceDotDDir); + + if (runOpts.sliceDMemoryLimit != null) { + Path memoryConfig = sliceDotDDir.resolve(Path.of(SLICE_D_MEM_CONFIG_FILE)); + Files.writeString(memoryConfig, getMemoryDSliceContent(runOpts)); + } + if (runOpts.sliceDCpuLimit != null) { + Path cpuConfig = sliceDotDDir.resolve(Path.of(SLICE_D_CPU_CONFIG_FILE)); + Files.writeString(cpuConfig, getCPUDSliceContent(runOpts)); + } + } + + Path memory, cpu; + try { + // memory slice + memory = SYSTEMD_CONFIG_HOME.resolve(Path.of(sliceFileName(sliceName))); + // cpu slice nested in memory + cpu = SYSTEMD_CONFIG_HOME.resolve(Path.of(sliceFileName(sliceNameCpu))); + Files.writeString(memory, memorySliceContent); + Files.writeString(cpu, cpuSliceContent); + } catch (IOException e) { + throw new AssertionError("Failed to write systemd slice files"); + } + + systemdDaemonReload(cpu); + + return new ResultFiles(memory, cpu, sliceDotDDir); + } + + private static String sliceName(SystemdRunOptions runOpts) { + // Slice name may include '-' which is a hierarchical slice indicator. + // Replace '-' with '_' to avoid side-effects. + return SLICE_NAMESPACE_PREFIX + "-" + runOpts.sliceName.replace("-", "_"); + } + + private static String sliceNameCpu(SystemdRunOptions runOpts) { + String slice = sliceName(runOpts); + return String.format("%s-cpu", slice); + } + + private static void systemdDaemonReload(Path cpu) throws Exception { + List daemonReload = systemCtl(); + daemonReload.add("daemon-reload"); + + if (execute(daemonReload).getExitValue() != 0) { + throw new AssertionError("Failed to reload systemd daemon"); + } + } + + private static List systemCtl() { + return commandWithUser("systemctl"); + } + + /** + * 'baseCommand' or 'baseCommand --user' as list, depending on the cgroups + * version and running user. + * + * @return 'baseCommand' if we are the root user, 'systemctl --user' if + * the current user is non-root and we are on cgroups v2. Note: + * Cgroups v1 and non-root is not possible as tests are skipped then. + */ + private static List commandWithUser(String baseCommand) { + List command = new ArrayList<>(); + command.add(baseCommand); + if (RUN_AS_USER) { + command.add("--user"); + } + return command; + } + + private static String getCpuSlice(SystemdRunOptions runOpts, String sliceName) { + String basicSliceFormat = getBasicSliceFormat(); + return String.format(basicSliceFormat, sliceName, getCPUSliceContent(runOpts)); + } + + private static String getCPUSliceContent(SystemdRunOptions runOpts) { + String format = basicCPUContentFormat(); + return String.format(format, runOpts.cpuLimit); + } + + private static String getMemorySlice(SystemdRunOptions runOpts, String sliceName) { + String basicSliceFormat = getBasicSliceFormat(); + return String.format(basicSliceFormat, sliceName, getMemorySliceContent(runOpts)); + } + + private static String getMemoryDSliceContent(SystemdRunOptions runOpts) { + String format = "[Slice]\n" + basicMemoryContentFormat(); + return String.format(format, runOpts.sliceDMemoryLimit); + } + + private static String getCPUDSliceContent(SystemdRunOptions runOpts) { + String format = "[Slice]\n" + basicCPUContentFormat(); + return String.format(format, runOpts.sliceDCpuLimit); + } + + private static String basicCPUContentFormat() { + return """ + CPUAccounting=true + CPUQuota=%s + """; + } + + private static String basicMemoryContentFormat() { + return """ + MemoryAccounting=true + MemoryLimit=%s + """; + } + + private static String getMemorySliceContent(SystemdRunOptions runOpts) { + String format = basicMemoryContentFormat(); + + return String.format(format, runOpts.memoryLimit); + } + + private static String getBasicSliceFormat() { + return """ + [Unit] + Description=OpenJDK Tests Slice for %s + Before=slices.target + + [Slice] + %s + """; + } + + private static String sliceFileName(String sliceName) { + return String.format("%s.slice", sliceName); + } + + /** + * Build the java command to run inside a systemd slice + * + * @param SystemdRunOptions options for running the systemd slice test + * + * @return command + * @throws Exception + */ + private static List buildJavaCommand(SystemdRunOptions opts) throws Exception { + // systemd-run [--user] --slice .slice --scope + List javaCmd = systemdRun(); + javaCmd.add("--slice"); + javaCmd.add(sliceFileName(sliceNameCpu(opts))); + javaCmd.add("--scope"); + javaCmd.add(Path.of(Utils.TEST_JDK, "bin", "java").toString()); + javaCmd.addAll(opts.javaOpts); + javaCmd.add(opts.classToRun); + javaCmd.addAll(opts.classParams); + return javaCmd; + } + + private static List systemdRun() { + return commandWithUser("systemd-run"); + } + + /** + * Execute a specified command in a process, report diagnostic info. + * + * @param command to be executed + * @return The output from the process + * @throws Exception + */ + private static OutputAnalyzer execute(List command) throws Exception { + return execute(command.toArray(String[]::new)); + } + + /** + * Execute a specified command in a process, report diagnostic info. + * + * @param command to be executed + * @return The output from the process + * @throws Exception + */ + private static OutputAnalyzer execute(String... command) throws Exception { + ProcessBuilder pb = new ProcessBuilder(command); + System.out.println("[COMMAND]\n" + Utils.getCommandLine(pb)); + + Process p = pb.start(); + long pid = p.pid(); + OutputAnalyzer output = new OutputAnalyzer(p); + + int max = MAX_LINES_TO_COPY_FOR_CHILD_STDOUT; + String stdout = output.getStdout(); + String stdoutLimited = limitLines(stdout, max); + System.out.println("[STDERR]\n" + output.getStderr()); + System.out.println("[STDOUT]\n" + stdoutLimited); + if (stdout != stdoutLimited) { + System.out.printf("Child process STDOUT is limited to %d lines\n", + max); + } + + String stdoutLogFile = String.format("systemd-stdout-%d.log", pid); + writeOutputToFile(stdout, stdoutLogFile); + System.out.println("Full child process STDOUT was saved to " + stdoutLogFile); + + return output; + } + + private static void writeOutputToFile(String output, String fileName) throws Exception { + try (FileWriter fw = new FileWriter(fileName)) { + fw.write(output, 0, output.length()); + } + } + + private static String limitLines(String buffer, int nrOfLines) { + List l = Arrays.asList(buffer.split("\\R")); + if (l.size() < nrOfLines) { + return buffer; + } + + return String.join("\n", l.subList(0, nrOfLines)); + } +} diff --git a/test/lib/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/jdk/test/lib/process/OutputAnalyzer.java index 24bb18e3d4b..3c5be74558b 100644 --- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java +++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java @@ -40,7 +40,8 @@ public final class OutputAnalyzer { private static final String jvmwarningmsg = ".* VM warning:.*"; - private static final String deprecatedmsg = ".* VM warning:.* deprecated.*"; + private static final String VM_DEPRECATED_MSG = ".* VM warning:.* deprecated.*"; + private static final String OTHER_DEPRECATED_MSG = "^WARNING: .* is deprecated.*"; private static final String FATAL_ERROR_PAT = "# A fatal error has been detected.*"; @@ -182,7 +183,7 @@ public OutputAnalyzer stderrShouldBeEmptyIgnoreWarnings() { * If stderr was not empty */ public OutputAnalyzer stderrShouldBeEmptyIgnoreDeprecatedWarnings() { - if (!getStderr().replaceAll(deprecatedmsg + "\\R", "").isEmpty()) { + if (!getStderrNoDeprecatedWarnings().isEmpty()) { reportDiagnosticSummary(); throw new RuntimeException("stderr was not empty"); } @@ -603,6 +604,15 @@ public String getStderr() { return buffer.getStderr(); } + /** + * Get the contents of the stderr buffer, with known deprecation warning patterns removed + * + * @return stderr buffer, with known deprecation warnings removed + */ + public String getStderrNoDeprecatedWarnings() { + return getStderr().replaceAll(VM_DEPRECATED_MSG + "\\R", "").replaceAll(OTHER_DEPRECATED_MSG + "\\R", ""); + } + /** * Get the process exit value * @@ -689,7 +699,7 @@ public OutputAnalyzer stderrShouldMatchIgnoreVMWarnings(String pattern) { * @throws RuntimeException If the pattern was not found */ public OutputAnalyzer stderrShouldMatchIgnoreDeprecatedWarnings(String pattern) { - String stderr = getStderr().replaceAll(deprecatedmsg + "\\R", ""); + String stderr = getStderrNoDeprecatedWarnings(); Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); if (!matcher.find()) { reportDiagnosticSummary(); diff --git a/test/lib/jdk/test/lib/security/SeededSecureRandom.java b/test/lib/jdk/test/lib/security/SeededSecureRandom.java index f897677390e..305a91c41d2 100644 --- a/test/lib/jdk/test/lib/security/SeededSecureRandom.java +++ b/test/lib/jdk/test/lib/security/SeededSecureRandom.java @@ -65,4 +65,10 @@ public byte[] generateSeed(int numBytes) { rnd.nextBytes(out); return out; } + + public byte[] nBytes(int n) { + var out = new byte[n]; + nextBytes(out); + return out; + } } diff --git a/test/lib/jdk/test/lib/thread/TestThreadFactory.java b/test/lib/jdk/test/lib/thread/TestThreadFactory.java new file mode 100644 index 00000000000..ac5a6b74909 --- /dev/null +++ b/test/lib/jdk/test/lib/thread/TestThreadFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.thread; + +import java.util.concurrent.ThreadFactory; + +/* + This factory is used to start new threads in tests. + It supports creation of virtual threads when jtreg test.thread.factory plugin is enabled. +*/ + +public class TestThreadFactory { + + private static ThreadFactory threadFactory = "Virtual".equals(System.getProperty("test.thread.factory")) + ? virtualThreadFactory() : platformThreadFactory(); + + public static Thread newThread(Runnable task) { + return threadFactory.newThread(task); + } + + public static Thread newThread(Runnable task, String name) { + Thread t = threadFactory.newThread(task); + t.setName(name); + return t; + } + + private static ThreadFactory platformThreadFactory() { + return Thread.ofPlatform().factory(); + } + + private static ThreadFactory virtualThreadFactory() { + return Thread.ofVirtual().factory(); + } +} diff --git a/test/lib/jdk/test/lib/thread/VThreadRunner.java b/test/lib/jdk/test/lib/thread/VThreadRunner.java index ba69496a047..1b09e5e0d12 100644 --- a/test/lib/jdk/test/lib/thread/VThreadRunner.java +++ b/test/lib/jdk/test/lib/thread/VThreadRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,10 @@ package jdk.test.lib.thread; -import java.lang.reflect.Field; +import java.lang.management.ManagementFactory; import java.time.Duration; -import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicReference; +import jdk.management.VirtualThreadSchedulerMXBean; /** * Helper class to support tests running tasks in a virtual thread. @@ -133,39 +133,36 @@ public static void run(ThrowingRunnable task) throws X run(null, 0, task); } - /** - * Returns the virtual thread scheduler. - */ - private static ForkJoinPool defaultScheduler() { - try { - var clazz = Class.forName("java.lang.VirtualThread"); - var field = clazz.getDeclaredField("DEFAULT_SCHEDULER"); - field.setAccessible(true); - return (ForkJoinPool) field.get(null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - /** * Sets the virtual thread scheduler's target parallelism. + * + *

        Tests using this method should use "{@code @modules jdk.management}" to help + * test selection. + * * @return the previous parallelism level */ public static int setParallelism(int size) { - return defaultScheduler().setParallelism(size); + var bean = ManagementFactory.getPlatformMXBean(VirtualThreadSchedulerMXBean.class); + int parallelism = bean.getParallelism(); + bean.setParallelism(size); + return parallelism; } /** * Ensures that the virtual thread scheduler's target parallelism is at least * the given size. If the target parallelism is less than the given size then * it is changed to the given size. + * + *

        Tests using this method should use "{@code @modules jdk.management}" to help + * test selection. + * * @return the previous parallelism level */ public static int ensureParallelism(int size) { - ForkJoinPool pool = defaultScheduler(); - int parallelism = pool.getParallelism(); + var bean = ManagementFactory.getPlatformMXBean(VirtualThreadSchedulerMXBean.class); + int parallelism = bean.getParallelism(); if (size > parallelism) { - pool.setParallelism(size); + bean.setParallelism(size); } return parallelism; } diff --git a/test/lib/jdk/test/lib/util/ForceGC.java b/test/lib/jdk/test/lib/util/ForceGC.java index 19bbef1f7e4..e3587b9a2be 100644 --- a/test/lib/jdk/test/lib/util/ForceGC.java +++ b/test/lib/jdk/test/lib/util/ForceGC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -78,29 +78,30 @@ public static boolean waitFor(BooleanSupplier booleanSupplier, long timeout) { ReferenceQueue queue = new ReferenceQueue<>(); Object obj = new Object(); PhantomReference ref = new PhantomReference<>(obj, queue); - obj = null; - Reference.reachabilityFence(obj); - Reference.reachabilityFence(ref); + try { + obj = null; - int retries = (int)(timeout / 200); - for (; retries >= 0; retries--) { - if (booleanSupplier.getAsBoolean()) { - return true; - } + int retries = (int) (timeout / 200); + for (; retries >= 0; retries--) { + if (booleanSupplier.getAsBoolean()) { + return true; + } - System.gc(); + System.gc(); - try { - // The remove() will always block for the specified milliseconds - // if the reference has already been removed from the queue. - // But it is fine. For most cases, the 1st GC is sufficient - // to trigger and complete the cleanup. - queue.remove(200L); - } catch (InterruptedException ie) { - // ignore, the loop will try again + try { + // The remove() will always block for the specified milliseconds + // if the reference has already been removed from the queue. + // But it is fine. For most cases, the 1st GC is sufficient + // to trigger and complete the cleanup. + queue.remove(200L); + } catch (InterruptedException ie) { + // ignore, the loop will try again + } } + } finally { + Reference.reachabilityFence(ref); } - return booleanSupplier.getAsBoolean(); } } diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 607e9552945..8883e8332d5 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -769,6 +769,7 @@ public native int validateCgroup(String procCgroups, public native void printOsInfo(); public native long hostPhysicalMemory(); public native long hostPhysicalSwap(); + public native int hostCPUs(); // Decoder public native void disableElfSectionCache(); diff --git a/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java b/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java new file mode 100644 index 00000000000..a124b079268 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.classfile; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.*; +import java.lang.constant.*; +import java.nio.charset.StandardCharsets; +import java.util.HexFormat; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.*; + +import jdk.internal.classfile.impl.*; +/** + * Test various operations on + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 1, time = 2) +@Measurement(iterations = 3, time = 1) +@Fork(jvmArgsAppend = "--enable-preview", value = 3) +@State(Scope.Thread) +public class Utf8EntryWriteTo { + static final ClassDesc STRING_BUILDER = ClassDesc.ofDescriptor("Ljava/lang/StringBuilder;"); + static final MethodTypeDesc MTD_append = MethodTypeDesc.of(STRING_BUILDER, CD_String); + static final MethodTypeDesc MTD_String = MethodTypeDesc.of(CD_String); + static final ClassDesc CLASS_DESC = ClassDesc.ofDescriptor("Lorg/openjdk/bench/java/lang/classfile/String$$StringConcat;"); + + @Param({"ascii", "utf8_2_bytes", "utf8_3_bytes", "emoji"}) + public String charType; + ConstantPoolBuilder poolBuilder; + ClassEntry thisClass; + + @Setup + public void setup() throws Exception { + byte[] bytes = HexFormat.of().parseHex( + switch (charType) { + case "ascii" -> "78"; + case "utf8_2_bytes" -> "c2a9"; + case "utf8_3_bytes" -> "e6b8a9"; + case "emoji" -> "e29da3efb88f"; + default -> throw new IllegalArgumentException("bad charType: " + charType); + } + ); + String s = new String(bytes, 0, bytes.length, StandardCharsets.UTF_8); + String[] constants = new String[128]; + for (int i = 0; i < constants.length; i++) { + constants[i] = "A".repeat(i).concat(s); + } + + poolBuilder = ConstantPoolBuilder.of(); + thisClass = poolBuilder.classEntry(CLASS_DESC); + for (var c : constants) { + poolBuilder.utf8Entry(c); + } + } + + @Benchmark + public void writeTo(Blackhole bh) { + bh.consume(ClassFile + .of() + .build(thisClass, poolBuilder, (ClassBuilder clb) -> {})); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CopyTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/CopyTest.java new file mode 100644 index 00000000000..8996b1de117 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CopyTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.bench.java.lang.foreign; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.ByteBuffer; +import java.util.concurrent.TimeUnit; + +import static java.lang.foreign.ValueLayout.*; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3) +public class CopyTest { + + @Param({"0", "1", "2", "3", "4", "5", "6", "7", "8", + "9", "10", "11", "12", "13", "14", "15", "16", + "17", "18", "19", "20", "21", "22", "23", "24", + "25", "26", "27", "28", "29", "30", "31", "32", + "33", "36", "40", "44", "48", "52", "56", "60", "63", "64", "128"}) + public int ELEM_SIZE; + + byte[] srcArray; + byte[] dstArray; + MemorySegment heapSrcSegment; + MemorySegment heapDstSegment; + MemorySegment nativeSrcSegment; + MemorySegment nativeDstSegment; + ByteBuffer srcBuffer; + ByteBuffer dstBuffer; + + @Setup + public void setup() { + srcArray = new byte[ELEM_SIZE]; + dstArray = new byte[ELEM_SIZE]; + heapSrcSegment = MemorySegment.ofArray(srcArray); + heapDstSegment = MemorySegment.ofArray(dstArray); + nativeSrcSegment = Arena.ofAuto().allocate(ELEM_SIZE); + nativeDstSegment = Arena.ofAuto().allocate(ELEM_SIZE); + srcBuffer = ByteBuffer.wrap(srcArray); + dstBuffer = ByteBuffer.wrap(dstArray); + } + + @Benchmark + public void array_copy() { + System.arraycopy(srcArray, 0, dstArray, 0, ELEM_SIZE); + } + + @Benchmark + public void heap_segment_copy5Arg() { + MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); + } + + @Benchmark + public void native_segment_copy5Arg() { + MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); + } + + @Benchmark + public void heap_segment_copy7arg() { + MemorySegment.copy(heapSrcSegment, JAVA_BYTE, 0, heapDstSegment, JAVA_BYTE, 0, ELEM_SIZE); + } + + @Benchmark + public void buffer_copy() { + dstBuffer.put(srcBuffer); + } + +} diff --git a/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java b/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java index 4cf578889d1..4239f70504b 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/CodeAttributeTools.java @@ -23,24 +23,21 @@ package org.openjdk.bench.jdk.classfile; import java.io.IOException; +import java.lang.classfile.Attributes; import java.lang.constant.ClassDesc; import java.net.URI; -import java.nio.ByteBuffer; import java.nio.file.FileSystems; import java.nio.file.Files; -import java.util.Iterator; import java.util.ArrayList; import java.util.List; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassReader; -import java.lang.classfile.MethodModel; -import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.constant.MethodTypeDesc; import jdk.internal.classfile.impl.AbstractPseudoInstruction; -import jdk.internal.classfile.impl.CodeImpl; import jdk.internal.classfile.impl.LabelContext; import jdk.internal.classfile.impl.ClassFileImpl; +import jdk.internal.classfile.impl.RawBytecodeHelper; import jdk.internal.classfile.impl.SplitConstantPool; import jdk.internal.classfile.impl.StackCounter; import jdk.internal.classfile.impl.StackMapGenerator; @@ -70,7 +67,7 @@ record GenData(LabelContext labelContext, String methodName, MethodTypeDesc methodDesc, boolean isStatic, - ByteBuffer bytecode, + RawBytecodeHelper.CodeRange bytecode, ConstantPoolBuilder constantPool, List handlers) {} @@ -85,15 +82,14 @@ public void setup() throws IOException { var thisCls = clm.thisClass().asSymbol(); var cp = new SplitConstantPool((ClassReader)clm.constantPool()); for (var m : clm.methods()) { - m.code().ifPresent(com -> { - var bb = ByteBuffer.wrap(((CodeImpl)com).contents()); + m.findAttribute(Attributes.code()).ifPresent(com -> { data.add(new GenData( (LabelContext)com, thisCls, m.methodName().stringValue(), m.methodTypeSymbol(), (m.flags().flagsMask() & ClassFile.ACC_STATIC) != 0, - bb.slice(8, bb.getInt(4)), + RawBytecodeHelper.of(com.codeArray()), cp, com.exceptionHandlers().stream().map(eh -> (AbstractPseudoInstruction.ExceptionCatchImpl)eh).toList())); }); @@ -112,7 +108,7 @@ public void benchmarkStackMapsGenerator(Blackhole bh) { d.methodName(), d.methodDesc(), d.isStatic(), - d.bytecode().rewind(), + d.bytecode(), (SplitConstantPool)d.constantPool(), (ClassFileImpl)ClassFile.of(), d.handlers())); @@ -127,7 +123,7 @@ public void benchmarkStackCounter(Blackhole bh) { d.methodName(), d.methodDesc(), d.isStatic(), - d.bytecode().rewind(), + d.bytecode(), (SplitConstantPool)d.constantPool(), d.handlers())); } diff --git a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java index 9d4f6260440..a3e4445664c 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java +++ b/test/micro/org/openjdk/bench/vm/compiler/TypeVectorOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -38,6 +38,9 @@ public abstract class TypeVectorOperations { @Param({"512", /* "1024", */ "2048"}) public int COUNT; + private boolean[] boolsA; + private boolean[] boolsB; + private boolean[] resZ; private byte[] bytesA; private byte[] bytesB; private byte[] resB; @@ -58,6 +61,9 @@ public abstract class TypeVectorOperations { @Setup public void init() { + boolsA = new boolean[COUNT]; + boolsB = new boolean[COUNT]; + resZ = new boolean[COUNT]; bytesA = new byte[COUNT]; bytesB = new byte[COUNT]; resB = new byte[COUNT]; @@ -73,6 +79,8 @@ public void init() { resF = new float[COUNT]; for (int i = 0; i < COUNT; i++) { + boolsA[i] = r.nextBoolean(); + boolsB[i] = r.nextBoolean(); shorts[i] = (short) r.nextInt(Short.MAX_VALUE + 1); ints[i] = r.nextInt(); longs[i] = r.nextLong(); @@ -366,6 +374,13 @@ public void convertS2L() { } } + @Benchmark + public void andZ() { + for (int i = 0; i < COUNT; i++) { + resZ[i] = boolsA[i] & boolsB[i]; + } + } + @Benchmark @Fork(jvmArgsPrepend = {"-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov"}) public void cmoveD() {