diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 289eec3356b..7a24815d163 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, 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 @@ -389,6 +389,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" CXXFLAGS="$ORG_CXXFLAGS" + + # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72 + UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11) + CXX="$cxx_filtered" ]) # Check if a compiler is of the toolchain type we expect, and save the version diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4 index 349a04a089e..3fae951224e 100644 --- a/make/autoconf/util.m4 +++ b/make/autoconf/util.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, 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 @@ -199,7 +199,7 @@ AC_DEFUN([UTIL_GET_NON_MATCHING_VALUES], if test -z "$legal_values"; then $1="$2" else - result=`$GREP -Fvx "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fvx -- "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) @@ -226,7 +226,7 @@ AC_DEFUN([UTIL_GET_MATCHING_VALUES], if test -z "$illegal_values"; then $1="" else - result=`$GREP -Fx "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fx -- "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix index 9ca040794f3..fbb82a11fac 100644 --- a/make/data/hotspot-symbols/symbols-unix +++ b/make/data/hotspot-symbols/symbols-unix @@ -223,6 +223,7 @@ JVM_VirtualThreadEnd JVM_VirtualThreadMount JVM_VirtualThreadUnmount JVM_VirtualThreadHideFrames +JVM_VirtualThreadDisableSuspend # Scoped values JVM_EnsureMaterializedForStackWalk_func diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index b6298c00c9a..442a245f92f 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -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 @@ -1289,25 +1289,58 @@ 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.toFile().isFile() && !p.endsWith("jdk11_backward")) .forEach(p -> { try { String zone = null; String rule = null; String format = null; + boolean inVanguard = false; + boolean inRearguard = false; for (var line : Files.readAllLines(p)) { - if (line.contains("#STDOFF")) continue; + // Interpret the line in rearguard mode so that STD/DST + // correctly handles negative DST cases, such as "GMT/IST" + // vs. "IST/GMT" case for Europe/Dublin + if (inVanguard) { + if (line.startsWith("# Rearguard")) { + inVanguard = false; + inRearguard = true; + } + continue; + } else if (line.startsWith("# Vanguard")) { + inVanguard = true; + continue; + } + if (inRearguard) { + if (line.startsWith("# End of rearguard")) { + inRearguard = false; + continue; + } else { + if (line.startsWith("#\t")) { + line = line.substring(1); // omit # + } + } + } + if (line.isBlank() || line.matches("^[ \t]*#.*")) { + // ignore blank/comment lines + continue; + } + // remove comments in-line line = line.replaceAll("[ \t]*#.*", ""); // Zone line if (line.startsWith("Zone")) { + if (zone != null) { + tzdbShortNamesMap.put(zone, format + NBSP + rule); + } var zl = line.split("[ \t]+", -1); zone = zl[1]; rule = zl[3]; format = zl[4]; } else { if (zone != null) { - if (line.isBlank()) { + if (line.startsWith("Rule") || + line.startsWith("Link")) { tzdbShortNamesMap.put(zone, format + NBSP + rule); zone = null; rule = null; diff --git a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java index 561edbef034..9655e08016c 100644 --- a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java +++ b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Locale; @@ -339,9 +340,15 @@ private static void buildOtherTables() { validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6)); checkCurrencyCode(currencyCode); int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')]; - if (tableEntry == INVALID_COUNTRY_ENTRY || - (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 || - (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) { + + // Do not allow a future currency to be classified as an otherCurrency, + // otherwise it will leak out into Currency:getAvailableCurrencies + boolean futureCurrency = Arrays.asList(specialCaseNewCurrencies).contains(currencyCode); + boolean simpleCurrency = (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) == (currencyCode.charAt(2) - 'A'); + + // If neither a simple currency, or one defined in the future + // then the current currency is applicable to be added to the otherTable + if (!futureCurrency && !simpleCurrency) { if (otherCurrenciesCount == maxOtherCurrencies) { throw new RuntimeException("too many other currencies"); } diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 360ef7a747a..b83d6185062 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -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. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -282,7 +282,8 @@ void LIR_Assembler::osr_entry() { __ bind(L); } #endif - __ ldp(r19, r20, Address(OSR_buf, slot_offset)); + __ ldr(r19, Address(OSR_buf, slot_offset)); + __ ldr(r20, Address(OSR_buf, slot_offset + BytesPerWord)); __ str(r19, frame_map()->address_for_monitor_lock(i)); __ str(r20, frame_map()->address_for_monitor_object(i)); } diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index c7b45ff0dde..8694734c751 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -310,7 +310,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, uint int_args = 0; uint fp_args = 0; - uint stk_args = 0; // inc by 2 each time + uint stk_args = 0; for (int i = 0; i < total_args_passed; i++) { switch (sig_bt[i]) { @@ -322,8 +322,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_VOID: @@ -340,6 +341,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -348,8 +350,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_DOUBLE: @@ -357,6 +360,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -367,7 +371,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - return align_up(stk_args, 2); + return stk_args; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 481c3d09e58..635acd781f9 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -303,15 +303,19 @@ void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, } void InterpreterMacroAssembler::load_method_entry(Register cache, Register index, int bcp_offset) { + assert_different_registers(cache, index); + // Get index out of bytecode pointer get_index_at_bcp(index, bcp_offset, cache /* as tmp */, sizeof(u2)); + + // sizeof(ResolvedMethodEntry) is not a power of 2 on Arm, so can't use shift mov(cache, sizeof(ResolvedMethodEntry)); mul(index, index, cache); // Scale the index to be the entry index * sizeof(ResolvedMethodEntry) // load constant pool cache pointer ldr(cache, Address(FP, frame::interpreter_frame_cache_offset * wordSize)); // Get address of method entries array - ldr(cache, Address(cache, ConstantPoolCache::method_entries_offset())); + ldr(cache, Address(cache, in_bytes(ConstantPoolCache::method_entries_offset()))); add(cache, cache, Array::base_offset_in_bytes()); add(cache, cache, index); } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 9a65f9f09fe..716c7b7575e 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -441,7 +441,6 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - if (slot & 1) slot++; return slot; } diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index ba9a3fd7a9b..efaf78ee568 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -370,17 +370,16 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, if (index_size == sizeof(u4)) { __ load_resolved_indy_entry(Rcache, Rindex); __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedIndyEntry::num_parameters_offset()))); - __ check_stack_top(); - __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize)); } else { // Pop N words from the stack assert(index_size == sizeof(u2), "Can only be u2"); __ load_method_entry(Rcache, Rindex); - __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedIndyEntry::num_parameters_offset()))); - __ check_stack_top(); - __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize)); + __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedMethodEntry::num_parameters_offset()))); } + __ check_stack_top(); + __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize)); + __ convert_retval_to_tos(state); __ check_and_handle_popframe(); diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index e478f08c977..55a0120e7c7 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -3666,15 +3666,15 @@ void TemplateTable::prepare_invoke(Register Rcache, Register recv) { // load receiver if needed (after extra argument is pushed so parameter size is correct) if (load_receiver) { __ ldrh(recv, Address(Rcache, in_bytes(ResolvedMethodEntry::num_parameters_offset()))); - Address recv_addr = __ receiver_argument_address(Rstack_top, Rtemp, recv); - __ ldr(recv, recv_addr); + __ add(recv, Rstack_top, AsmOperand(recv, lsl, Interpreter::logStackElementSize)); + __ ldr(recv, Address(recv, -Interpreter::stackElementSize)); __ verify_oop(recv); } // load return address { const address table = (address) Interpreter::invoke_return_entry_table_for(code); - __ mov_slow(Rtemp, table); - __ ldr(LR, Address::indexed_ptr(Rtemp, ret_type)); + __ mov_slow(LR, table); + __ ldr(LR, Address::indexed_ptr(LR, ret_type)); } } @@ -3744,10 +3744,13 @@ void TemplateTable::invokevirtual(int byte_no) { void TemplateTable::invokespecial(int byte_no) { transition(vtos, vtos); assert(byte_no == f1_byte, "use this argument"); + const Register Rrecv = R2_tmp; - load_resolved_method_entry_special_or_static(R2_tmp, // ResolvedMethodEntry* + const Register Rflags = R3_tmp; + + load_resolved_method_entry_special_or_static(Rrecv, // ResolvedMethodEntry* Rmethod, // Method* - R3_tmp); // Flags + Rflags); // Flags prepare_invoke(Rrecv, Rrecv); __ verify_oop(Rrecv); __ null_check(Rrecv, Rtemp); @@ -3760,12 +3763,16 @@ void TemplateTable::invokespecial(int byte_no) { void TemplateTable::invokestatic(int byte_no) { transition(vtos, vtos); assert(byte_no == f1_byte, "use this argument"); - load_resolved_method_entry_special_or_static(R2_tmp, // ResolvedMethodEntry* + + const Register Rrecv = R2_tmp; + const Register Rflags = R3_tmp; + + load_resolved_method_entry_special_or_static(Rrecv, // ResolvedMethodEntry* Rmethod, // Method* - R3_tmp); // Flags - prepare_invoke(R2_tmp, R2_tmp); + Rflags); // Flags + prepare_invoke(Rrecv, Rrecv); // do the call - __ profile_call(R2_tmp); + __ profile_call(Rrecv); __ jump_from_interpreted(Rmethod); } @@ -3788,10 +3795,10 @@ void TemplateTable::invokeinterface(int byte_no) { const Register Rflags = R3_tmp; const Register Rklass = R2_tmp; // Note! Same register with Rrecv - load_resolved_method_entry_interface(R2_tmp, // ResolvedMethodEntry* - R1_tmp, // Klass* + load_resolved_method_entry_interface(Rrecv, // ResolvedMethodEntry* + Rinterf, // Klass* Rmethod, // Method* or itable/vtable index - R3_tmp); // Flags + Rflags); // Flags prepare_invoke(Rrecv, Rrecv); // First check for Object case, then private interface method, diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 824996168a9..3382df355da 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -734,7 +734,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, ShouldNotReachHere(); } } - return align_up(stk, 2); + return stk; } #if defined(COMPILER1) || defined(COMPILER2) diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 36430e126f9..582aa400875 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -266,7 +266,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, uint int_args = 0; uint fp_args = 0; - uint stk_args = 0; // inc by 2 each time + uint stk_args = 0; for (int i = 0; i < total_args_passed; i++) { switch (sig_bt[i]) { @@ -278,8 +278,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_VOID: @@ -295,6 +296,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -303,8 +305,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_DOUBLE: @@ -312,6 +315,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -321,7 +325,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - return align_up(stk_args, 2); + return stk_args; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 4798f35f19d..ed1795cfa33 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -755,7 +755,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, ShouldNotReachHere(); } } - return align_up(stk, 2); + return stk; } int SharedRuntime::c_calling_convention(const BasicType *sig_bt, diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 54e5f55fa2b..a197a8e3c7d 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1089,7 +1089,8 @@ void C2_MacroAssembler::vminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); - assert_different_registers(a, b, tmp, atmp, btmp); + assert_different_registers(a, tmp, atmp, btmp); + assert_different_registers(b, tmp, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); @@ -1176,7 +1177,8 @@ void C2_MacroAssembler::evminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); - assert_different_registers(dst, a, b, atmp, btmp); + assert_different_registers(dst, a, atmp, btmp); + assert_different_registers(dst, b, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index aec1f3c9105..88296656485 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1871,92 +1871,6 @@ void MacroAssembler::cmpoop(Register src1, jobject src2, Register rscratch) { } #endif -void MacroAssembler::cvtss2sd(XMMRegister dst, XMMRegister src) { - if ((UseAVX > 0) && (dst != src)) { - xorpd(dst, dst); - } - Assembler::cvtss2sd(dst, src); -} - -void MacroAssembler::cvtss2sd(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtss2sd(dst, src); -} - -void MacroAssembler::cvtsd2ss(XMMRegister dst, XMMRegister src) { - if ((UseAVX > 0) && (dst != src)) { - xorps(dst, dst); - } - Assembler::cvtsd2ss(dst, src); -} - -void MacroAssembler::cvtsd2ss(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsd2ss(dst, src); -} - -void MacroAssembler::cvtsi2sdl(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdl(dst, src); -} - -void MacroAssembler::cvtsi2sdl(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdl(dst, src); -} - -void MacroAssembler::cvtsi2ssl(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssl(dst, src); -} - -void MacroAssembler::cvtsi2ssl(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssl(dst, src); -} - -#ifdef _LP64 -void MacroAssembler::cvtsi2sdq(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdq(dst, src); -} - -void MacroAssembler::cvtsi2sdq(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdq(dst, src); -} - -void MacroAssembler::cvtsi2ssq(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssq(dst, src); -} - -void MacroAssembler::cvtsi2ssq(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssq(dst, src); -} -#endif // _LP64 - void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch) { assert(rscratch != noreg || always_reachable(adr), "missing"); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index ea6a37d16ed..1908703b9bf 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -800,23 +800,6 @@ class MacroAssembler: public Assembler { void cmpxchgptr(Register reg, Address adr); - - // cvt instructions - void cvtss2sd(XMMRegister dst, XMMRegister src); - void cvtss2sd(XMMRegister dst, Address src); - void cvtsd2ss(XMMRegister dst, XMMRegister src); - void cvtsd2ss(XMMRegister dst, Address src); - void cvtsi2sdl(XMMRegister dst, Register src); - void cvtsi2sdl(XMMRegister dst, Address src); - void cvtsi2ssl(XMMRegister dst, Register src); - void cvtsi2ssl(XMMRegister dst, Address src); -#ifdef _LP64 - void cvtsi2sdq(XMMRegister dst, Register src); - void cvtsi2sdq(XMMRegister dst, Address src); - void cvtsi2ssq(XMMRegister dst, Register src); - void cvtsi2ssq(XMMRegister dst, Address src); -#endif - void locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch = noreg); void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 3ae539bac8d..571160523cb 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -528,8 +528,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - // return value can be odd number of VMRegImpl stack slots make multiple of 2 - return align_up(stack, 2); + return stack; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index bf15dab0703..faa423bcf8e 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -498,7 +498,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, uint int_args = 0; uint fp_args = 0; - uint stk_args = 0; // inc by 2 each time + uint stk_args = 0; for (int i = 0; i < total_args_passed; i++) { switch (sig_bt[i]) { @@ -510,8 +510,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_VOID: @@ -528,6 +529,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -536,8 +538,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_DOUBLE: @@ -545,6 +548,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -555,7 +559,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - return align_up(stk_args, 2); + return stk_args; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 759dd8a1d48..80f281a1bf9 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -10095,7 +10095,7 @@ instruct cmpD_imm(rRegI dst, regD src, immD con, rFlagsReg cr) %{ instruct convF2D_reg_reg(regD dst, regF src) %{ match(Set dst (ConvF2D src)); - effect(TEMP dst); + format %{ "cvtss2sd $dst, $src" %} ins_encode %{ __ cvtss2sd ($dst$$XMMRegister, $src$$XMMRegister); @@ -10117,7 +10117,7 @@ instruct convF2D_reg_mem(regD dst, memory src) instruct convD2F_reg_reg(regF dst, regD src) %{ match(Set dst (ConvD2F src)); - effect(TEMP dst); + format %{ "cvtsd2ss $dst, $src" %} ins_encode %{ __ cvtsd2ss ($dst$$XMMRegister, $src$$XMMRegister); diff --git a/src/hotspot/share/c1/c1_FrameMap.cpp b/src/hotspot/share/c1/c1_FrameMap.cpp index c55e41f4583..ace4fe8209d 100644 --- a/src/hotspot/share/c1/c1_FrameMap.cpp +++ b/src/hotspot/share/c1/c1_FrameMap.cpp @@ -72,7 +72,7 @@ CallingConvention* FrameMap::java_calling_convention(const BasicTypeArray* signa } } - intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); + intptr_t out_preserve = align_up(SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs), 2); LIR_OprList* args = new LIR_OprList(signature->length()); for (i = 0; i < sizeargs;) { BasicType t = sig_bt[i]; diff --git a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp index 4af9f29f263..256f8190b50 100644 --- a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp +++ b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp @@ -421,8 +421,11 @@ void RangeCheckEliminator::add_access_indexed_info(InstructionList &indices, int aii->_max = idx; aii->_list = new AccessIndexedList(); } else if (idx >= aii->_min && idx <= aii->_max) { - remove_range_check(ai); - return; + // Guard against underflow/overflow (see 'range_cond' check in RangeCheckEliminator::in_block_motion) + if (aii->_max < 0 || (aii->_max + min_jint) <= aii->_min) { + remove_range_check(ai); + return; + } } aii->_min = MIN2(aii->_min, idx); aii->_max = MAX2(aii->_max, idx); @@ -465,9 +468,9 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList } } } else { - int last_integer = 0; + jint last_integer = 0; Instruction *last_instruction = index; - int base = 0; + jint base = 0; ArithmeticOp *ao = index->as_ArithmeticOp(); while (ao != nullptr && (ao->x()->as_Constant() || ao->y()->as_Constant()) && (ao->op() == Bytecodes::_iadd || ao->op() == Bytecodes::_isub)) { @@ -479,12 +482,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList } if (c) { - int value = c->type()->as_IntConstant()->value(); + jint value = c->type()->as_IntConstant()->value(); if (value != min_jint) { if (ao->op() == Bytecodes::_isub) { value = -value; } - base += value; + base = java_add(base, value); last_integer = base; last_instruction = other; } @@ -506,12 +509,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList assert(info != nullptr, "Info must not be null"); // if idx < 0, max > 0, max + idx may fall between 0 and - // length-1 and if min < 0, min + idx may overflow and be >= + // length-1 and if min < 0, min + idx may underflow/overflow and be >= // 0. The predicate wouldn't trigger but some accesses could // be with a negative index. This test guarantees that for the // min and max value that are kept the predicate can't let // some incorrect accesses happen. - bool range_cond = (info->_max < 0 || info->_max + min_jint <= info->_min); + bool range_cond = (info->_max < 0 || (info->_max + min_jint) <= info->_min); // Generate code only if more than 2 range checks can be eliminated because of that. // 2 because at least 2 comparisons are done @@ -859,7 +862,7 @@ void RangeCheckEliminator::process_access_indexed(BlockBegin *loop_header, Block ); remove_range_check(ai); - } else if (_optimistic && loop_header) { + } else if (false && _optimistic && loop_header) { assert(ai->array(), "Array must not be null!"); assert(ai->index(), "Index must not be null!"); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 99acbb4ace8..e7225cb977b 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -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 @@ -576,12 +576,14 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) { const char* file = ClassLoader::skip_uri_protocol(location->as_C_string()); for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) { SharedClassPathEntry* ent = shared_path(i); - assert(ent->in_named_module(), "must be"); - bool cond = strcmp(file, ent->name()) == 0; - log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i, - location->as_C_string(), ent->name(), cond ? "same" : "different"); - if (cond) { - return i; + if (!ent->is_non_existent()) { + assert(ent->in_named_module(), "must be"); + bool cond = strcmp(file, ent->name()) == 0; + log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i, + location->as_C_string(), ent->name(), cond ? "same" : "different"); + if (cond) { + return i; + } } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 7ad7b62b760..51de517e50c 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.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 @@ -89,6 +89,7 @@ class SharedClassPathEntry : public MetaspaceObj { bool is_dir() const { return _type == dir_entry; } bool is_modules_image() const { return _type == modules_image_entry; } bool is_jar() const { return _type == jar_entry; } + bool is_non_existent() const { return _type == non_existent_entry; } bool from_class_path_attr() { return _from_class_path_attr; } time_t timestamp() const { return _timestamp; } const char* name() const; diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 4aa95aff0e1..743bd9d06ba 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -2257,11 +2257,12 @@ void ClassVerifier::verify_switch( "low must be less than or equal to high in tableswitch"); return; } - keys = high - low + 1; - if (keys < 0) { + int64_t keys64 = ((int64_t)high - low) + 1; + if (keys64 > 65535) { // Max code length verify_error(ErrorContext::bad_code(bci), "too many keys in tableswitch"); return; } + keys = (int)keys64; delta = 1; } else { keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize); diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 8ed99d74c0b..c9bc4acbeff 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -597,6 +597,7 @@ class methodHandle; do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_RN) \ + do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_RN) \ \ /* support for UnsafeConstants */ \ do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 16ddc2602b1..fb4b059b5bd 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -421,6 +421,7 @@ class SerializeClosure; template(notifyJvmtiMount_name, "notifyJvmtiMount") \ template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \ template(notifyJvmtiHideFrames_name, "notifyJvmtiHideFrames") \ + template(notifyJvmtiDisableSuspend_name, "notifyJvmtiDisableSuspend") \ template(doYield_name, "doYield") \ template(enter_name, "enter") \ template(enterSpecial_name, "enterSpecial") \ diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 64adc566a24..75582201087 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -3017,7 +3017,7 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bo assert(sig_index == sizeargs, ""); } const char* spname = "sp"; // make arch-specific? - intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); + SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); int stack_slot_offset = this->frame_size() * wordSize; int tab1 = 14, tab2 = 24; int sig_index = 0; diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index ec32f8b589b..b52bfdfbb08 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -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 @@ -403,7 +403,7 @@ class G1PrepareEvacuationTask : public WorkerTask { _g1h->register_region_with_region_attr(hr); } log_debug(gc, humongous)("Humongous region %u (object size %zu @ " PTR_FORMAT ") remset %zu code roots %zu " - "marked %d pinned count %u reclaim candidate %d type array %d", + "marked %d pinned count %zu reclaim candidate %d type array %d", index, cast_to_oop(hr->bottom())->size() * HeapWordSize, p2i(hr->bottom()), diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index 29fe5031a35..69040028d98 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -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 @@ -424,7 +424,7 @@ void HeapRegion::print_on(outputStream* st) const { st->print("|-"); } } - st->print("|%3u", Atomic::load(&_pinned_object_count)); + st->print("|%3zu", Atomic::load(&_pinned_object_count)); st->print_cr(""); } diff --git a/src/hotspot/share/gc/g1/heapRegion.hpp b/src/hotspot/share/gc/g1/heapRegion.hpp index 2706b814000..725433215c4 100644 --- a/src/hotspot/share/gc/g1/heapRegion.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.hpp @@ -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 @@ -257,7 +257,7 @@ class HeapRegion : public CHeapObj { uint _node_index; // Number of objects in this region that are currently pinned. - volatile uint _pinned_object_count; + volatile size_t _pinned_object_count; void report_region_type_change(G1HeapRegionTraceType::Type to); @@ -408,7 +408,7 @@ class HeapRegion : public CHeapObj { bool is_old_or_humongous() const { return _type.is_old_or_humongous(); } - uint pinned_count() const { return Atomic::load(&_pinned_object_count); } + size_t pinned_count() const { return Atomic::load(&_pinned_object_count); } bool has_pinned_objects() const { return pinned_count() > 0; } void set_free(); diff --git a/src/hotspot/share/gc/g1/heapRegion.inline.hpp b/src/hotspot/share/gc/g1/heapRegion.inline.hpp index ec68407b546..4a42b922182 100644 --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp @@ -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 @@ -554,11 +554,11 @@ inline void HeapRegion::record_surv_words_in_group(size_t words_survived) { } inline void HeapRegion::increment_pinned_object_count() { - Atomic::add(&_pinned_object_count, 1u, memory_order_relaxed); + Atomic::add(&_pinned_object_count, (size_t)1, memory_order_relaxed); } inline void HeapRegion::decrement_pinned_object_count() { - Atomic::sub(&_pinned_object_count, 1u, memory_order_relaxed); + Atomic::sub(&_pinned_object_count, (size_t)1, memory_order_relaxed); } #endif // SHARE_GC_G1_HEAPREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/vmStructs_g1.hpp b/src/hotspot/share/gc/g1/vmStructs_g1.hpp index 94ade0f387c..9ce61531989 100644 --- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp +++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, 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 @@ -41,7 +41,7 @@ nonstatic_field(HeapRegion, _bottom, HeapWord* const) \ nonstatic_field(HeapRegion, _top, HeapWord* volatile) \ nonstatic_field(HeapRegion, _end, HeapWord* const) \ - nonstatic_field(HeapRegion, _pinned_object_count, volatile uint) \ + volatile_nonstatic_field(HeapRegion, _pinned_object_count, size_t) \ \ nonstatic_field(HeapRegionType, _tag, HeapRegionType::Tag volatile) \ \ diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index b64c5050a22..49e43c284fa 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -31,6 +31,7 @@ #include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" +#include "runtime/safepoint.hpp" WorkerTaskDispatcher::WorkerTaskDispatcher() : _task(nullptr), @@ -141,40 +142,44 @@ void WorkerThreads::threads_do(ThreadClosure* tc) const { } } -void WorkerThreads::set_indirectly_suspendible_threads() { +template +void WorkerThreads::threads_do_f(Function function) const { + for (uint i = 0; i < _created_workers; i++) { + function(_workers[i]); + } +} + +void WorkerThreads::set_indirect_states() { #ifdef ASSERT - class SetIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { + const bool is_suspendible = Thread::current()->is_suspendible_thread(); + const bool is_safepointed = Thread::current()->is_VM_thread() && SafepointSynchronize::is_at_safepoint(); + + threads_do_f([&](Thread* thread) { + assert(!thread->is_indirectly_suspendible_thread(), "Unexpected"); + assert(!thread->is_indirectly_safepoint_thread(), "Unexpected"); + if (is_suspendible) { thread->set_indirectly_suspendible_thread(); } - }; - - if (Thread::current()->is_suspendible_thread()) { - SetIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + if (is_safepointed) { + thread->set_indirectly_safepoint_thread(); + } + }); #endif } -void WorkerThreads::clear_indirectly_suspendible_threads() { +void WorkerThreads::clear_indirect_states() { #ifdef ASSERT - class ClearIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { - thread->clear_indirectly_suspendible_thread(); - } - }; - - if (Thread::current()->is_suspendible_thread()) { - ClearIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + threads_do_f([&](Thread* thread) { + thread->clear_indirectly_suspendible_thread(); + thread->clear_indirectly_safepoint_thread(); + }); #endif } void WorkerThreads::run_task(WorkerTask* task) { - set_indirectly_suspendible_threads(); + set_indirect_states(); _dispatcher.coordinator_distribute_task(task, _active_workers); - clear_indirectly_suspendible_threads(); + clear_indirect_states(); } void WorkerThreads::run_task(WorkerTask* task, uint num_workers) { diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp index 39687e2581c..642c8d93f59 100644 --- a/src/hotspot/share/gc/shared/workerThread.hpp +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -93,8 +93,8 @@ class WorkerThreads : public CHeapObj { WorkerThread* create_worker(uint name_suffix); - void set_indirectly_suspendible_threads(); - void clear_indirectly_suspendible_threads(); + void set_indirect_states(); + void clear_indirect_states(); protected: virtual void on_create_worker(WorkerThread* worker) {} @@ -111,6 +111,8 @@ class WorkerThreads : public CHeapObj { uint set_active_workers(uint num_workers); void threads_do(ThreadClosure* tc) const; + template + void threads_do_f(Function function) const; const char* name() const { return _name; } diff --git a/src/hotspot/share/gc/z/zBarrier.inline.hpp b/src/hotspot/share/gc/z/zBarrier.inline.hpp index e0d83619934..2c81c14865b 100644 --- a/src/hotspot/share/gc/z/zBarrier.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrier.inline.hpp @@ -26,14 +26,13 @@ #include "gc/z/zBarrier.hpp" -#include "code/codeCache.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zHeap.inline.hpp" #include "gc/z/zResurrection.inline.hpp" +#include "gc/z/zVerify.hpp" #include "oops/oop.hpp" #include "runtime/atomic.hpp" -#include "runtime/continuation.hpp" // A self heal must always "upgrade" the address metadata bits in // accordance with the metadata bits state machine. The following @@ -320,17 +319,9 @@ inline zaddress ZBarrier::make_load_good_no_relocate(zpointer o) { return remap(ZPointer::uncolor_unsafe(o), remap_generation(o)); } -inline void z_assert_is_barrier_safe() { - assert(!Thread::current()->is_ConcurrentGC_thread() || /* Need extra checks for ConcurrentGCThreads */ - Thread::current()->is_suspendible_thread() || /* Thread prevents safepoints */ - Thread::current()->is_indirectly_suspendible_thread() || /* Coordinator thread prevents safepoints */ - SafepointSynchronize::is_at_safepoint(), /* Is at safepoint */ - "Shouldn't perform load barrier"); -} - template inline zaddress ZBarrier::barrier(ZBarrierFastPath fast_path, ZBarrierSlowPath slow_path, ZBarrierColor color, volatile zpointer* p, zpointer o, bool allow_null) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); // Fast path if (fast_path(o)) { diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 4621101eb88..bb0653f72ea 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -286,6 +286,10 @@ void ZGeneration::desynchronize_relocation() { _relocate.desynchronize(); } +bool ZGeneration::is_relocate_queue_active() const { + return _relocate.is_queue_active(); +} + void ZGeneration::reset_statistics() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); _freed = 0; @@ -1496,7 +1500,7 @@ void ZGenerationOld::remap_young_roots() { uint remap_nworkers = clamp(ZGeneration::young()->workers()->active_workers() + prev_nworkers, 1u, ZOldGCThreads); _workers.set_active_workers(remap_nworkers); - // TODO: The STS joiner is only needed to satisfy z_assert_is_barrier_safe that doesn't + // TODO: The STS joiner is only needed to satisfy ZBarrier::assert_is_state_barrier_safe that doesn't // understand the driver locker. Consider making the assert aware of the driver locker. SuspendibleThreadSetJoiner sts_joiner; diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 23736f45b7b..32762a50b62 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -166,6 +166,7 @@ class ZGeneration { // Relocation void synchronize_relocation(); void desynchronize_relocation(); + bool is_relocate_queue_active() const; zaddress relocate_or_remap_object(zaddress_unsafe addr); zaddress remap_object(zaddress_unsafe addr); diff --git a/src/hotspot/share/gc/z/zIterator.inline.hpp b/src/hotspot/share/gc/z/zIterator.inline.hpp index 9ccacdc9a3c..af97a549b0d 100644 --- a/src/hotspot/share/gc/z/zIterator.inline.hpp +++ b/src/hotspot/share/gc/z/zIterator.inline.hpp @@ -26,11 +26,21 @@ #include "gc/z/zIterator.hpp" +#include "gc/z/zVerify.hpp" #include "memory/iterator.inline.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" inline bool ZIterator::is_invisible_object(oop obj) { + // This is a good place to make sure that we can't concurrently iterate over + // objects while VMThread operations think they have exclusive access to the + // object graph. + // + // One example that have caused problems is the JFR Leak Profiler, which + // sets the mark word to a value that makes the object arrays look like + // invisible objects. + z_verify_safepoints_are_blocked(); + return obj->mark_acquire().is_marked(); } diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 60a6616d0a7..78efa7cdb12 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -87,6 +87,7 @@ ZRelocateQueue::ZRelocateQueue() _nworkers(0), _nsynchronized(0), _synchronize(false), + _is_active(false), _needs_attention(0) {} bool ZRelocateQueue::needs_attention() const { @@ -103,6 +104,20 @@ void ZRelocateQueue::dec_needs_attention() { assert(needs_attention == 0 || needs_attention == 1, "Invalid state"); } +void ZRelocateQueue::activate(uint nworkers) { + _is_active = true; + join(nworkers); +} + +void ZRelocateQueue::deactivate() { + Atomic::store(&_is_active, false); + clear(); +} + +bool ZRelocateQueue::is_active() const { + return Atomic::load(&_is_active); +} + void ZRelocateQueue::join(uint nworkers) { assert(nworkers != 0, "Must request at least one worker"); assert(_nworkers == 0, "Invalid state"); @@ -327,7 +342,7 @@ ZWorkers* ZRelocate::workers() const { } void ZRelocate::start() { - _queue.join(workers()->active_workers()); + _queue.activate(workers()->active_workers()); } void ZRelocate::add_remset(volatile zpointer* p) { @@ -1088,6 +1103,9 @@ class ZRelocateTask : public ZRestartableTask { ~ZRelocateTask() { _generation->stat_relocation()->at_relocate_end(_small_allocator.in_place_count(), _medium_allocator.in_place_count()); + + // Signal that we're not using the queue anymore. Used mostly for asserts. + _queue->deactivate(); } virtual void work() { @@ -1232,8 +1250,6 @@ void ZRelocate::relocate(ZRelocationSet* relocation_set) { ZRelocateAddRemsetForFlipPromoted task(relocation_set->flip_promoted_pages()); workers()->run(&task); } - - _queue.clear(); } ZPageAge ZRelocate::compute_to_age(ZPageAge from_age) { @@ -1316,3 +1332,7 @@ void ZRelocate::desynchronize() { ZRelocateQueue* ZRelocate::queue() { return &_queue; } + +bool ZRelocate::is_queue_active() const { + return _queue.is_active(); +} diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index ed54103d53c..1b35abdf521 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -41,6 +41,7 @@ class ZRelocateQueue { uint _nworkers; uint _nsynchronized; bool _synchronize; + volatile bool _is_active; volatile int _needs_attention; bool needs_attention() const; @@ -53,6 +54,10 @@ class ZRelocateQueue { public: ZRelocateQueue(); + void activate(uint nworkers); + void deactivate(); + bool is_active() const; + void join(uint nworkers); void resize_workers(uint nworkers); void leave(); @@ -99,6 +104,8 @@ class ZRelocate { void desynchronize(); ZRelocateQueue* queue(); + + bool is_queue_active() const; }; #endif // SHARE_GC_Z_ZRELOCATE_HPP diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index 83bdf13b2bb..92f245777b4 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -106,11 +106,16 @@ class ZRelocationSetInstallTask : public ZTask { } virtual void work() { + // Join the STS to block out VMThreads while running promote_barrier_on_young_oop_field + SuspendibleThreadSetJoiner sts_joiner; + // Allocate and install forwardings for small pages for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_small(forwarding, _medium->length() + page_index); + + SuspendibleThreadSet::yield(); } // Allocate and install forwardings for medium pages @@ -118,6 +123,8 @@ class ZRelocationSetInstallTask : public ZTask { ZPage* page = _medium->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_medium(forwarding, page_index); + + SuspendibleThreadSet::yield(); } } diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp index 3eb28d3cafe..a7d39e5ed9c 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp @@ -29,11 +29,12 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zBarrier.inline.hpp" #include "gc/z/zHeap.inline.hpp" +#include "gc/z/zBarrier.hpp" #include "oops/oop.hpp" template inline void ZUncoloredRoot::barrier(ObjectFunctionT function, zaddress_unsafe* p, uintptr_t color) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); const zaddress_unsafe addr = Atomic::load(p); assert_is_valid(addr); diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 6950f669158..b168610db3a 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -43,16 +43,67 @@ #include "runtime/frame.inline.hpp" #include "runtime/globals.hpp" #include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" +#include "runtime/javaThread.inline.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stackWatermark.inline.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/thread.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/preserveException.hpp" #include "utilities/resourceHash.hpp" +#ifdef ASSERT + +// Used to verify that safepoints operations can't be scheduled concurrently +// with callers to this function. Typically used to verify that object oops +// and headers are safe to access. +void z_verify_safepoints_are_blocked() { + Thread* current = Thread::current(); + + if (current->is_ConcurrentGC_thread()) { + assert(current->is_suspendible_thread(), // Thread prevents safepoints + "Safepoints are not blocked by current thread"); + + } else if (current->is_Worker_thread()) { + assert(// Check if ... + // the thread prevents safepoints + current->is_suspendible_thread() || + // the coordinator thread is the safepointing VMThread + current->is_indirectly_safepoint_thread() || + // the coordinator thread prevents safepoints + current->is_indirectly_suspendible_thread() || + // the RelocateQueue prevents safepoints + // + // RelocateQueue acts as a pseudo STS leaver/joiner and blocks + // safepoints. There's currently no infrastructure to check if the + // current thread is active or not, so check the global states instead. + ZGeneration::young()->is_relocate_queue_active() || + ZGeneration::old()->is_relocate_queue_active(), + "Safepoints are not blocked by current thread"); + + } else if (current->is_Java_thread()) { + JavaThreadState state = JavaThread::cast(current)->thread_state(); + assert(state == _thread_in_Java || state == _thread_in_vm || state == _thread_new, + "Safepoints are not blocked by current thread from state: %d", state); + + } else if (current->is_JfrSampler_thread()) { + // The JFR sampler thread blocks out safepoints with this lock. + assert_lock_strong(Threads_lock); + + } else if (current->is_VM_thread()) { + // The VM Thread doesn't schedule new safepoints while executing + // other safepoint or handshake operations. + + } else { + fatal("Unexpected thread type"); + } +} + +#endif + #define BAD_OOP_ARG(o, p) "Bad oop " PTR_FORMAT " found at " PTR_FORMAT, untype(o), p2i(p) static bool z_is_null_relaxed(zpointer o) { diff --git a/src/hotspot/share/gc/z/zVerify.hpp b/src/hotspot/share/gc/z/zVerify.hpp index e9ada2cefa9..447d38504a2 100644 --- a/src/hotspot/share/gc/z/zVerify.hpp +++ b/src/hotspot/share/gc/z/zVerify.hpp @@ -30,6 +30,8 @@ class frame; class ZForwarding; class ZPageAllocator; +NOT_DEBUG(inline) void z_verify_safepoints_are_blocked() NOT_DEBUG_RETURN; + class ZVerify : public AllStatic { private: static void roots_strong(bool verify_after_old_mark); diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index cc1b3d94cbd..5d6ab27a3a1 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1154,6 +1154,9 @@ JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide); JNIEXPORT void JNICALL JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide); +JNIEXPORT void JNICALL +JVM_VirtualThreadDisableSuspend(JNIEnv* env, jobject vthread, jboolean enter); + /* * Core reflection support. */ diff --git a/src/hotspot/share/interpreter/bytecodes.cpp b/src/hotspot/share/interpreter/bytecodes.cpp index 89dab8382d3..44d1fd668d6 100644 --- a/src/hotspot/share/interpreter/bytecodes.cpp +++ b/src/hotspot/share/interpreter/bytecodes.cpp @@ -385,13 +385,18 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) if (end != nullptr && aligned_bcp + 3*jintSize >= end) { return -1; // don't read past end of code buffer } - // Promote calculation to 64 bits to do range checks, used by the verifier. + // Promote calculation to signed 64 bits to do range checks, used by the verifier. int64_t lo = (int)Bytes::get_Java_u4(aligned_bcp + 1*jintSize); int64_t hi = (int)Bytes::get_Java_u4(aligned_bcp + 2*jintSize); int64_t len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize; - // only return len if it can be represented as a positive int; - // return -1 otherwise - return (len > 0 && len == (int)len) ? (int)len : -1; + // Only return len if it can be represented as a positive int and lo <= hi. + // The caller checks for bytecode stream overflow. + if (lo <= hi && len == (int)len) { + assert(len > 0, "must be"); + return (int)len; + } else { + return -1; + } } case _lookupswitch: // fall through @@ -404,9 +409,13 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) // Promote calculation to 64 bits to do range checks, used by the verifier. int64_t npairs = (int)Bytes::get_Java_u4(aligned_bcp + jintSize); int64_t len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize; - // only return len if it can be represented as a positive int; - // return -1 otherwise - return (len > 0 && len == (int)len) ? (int)len : -1; + // Only return len if it can be represented as a positive int and npairs >= 0. + if (npairs >= 0 && len == (int)len) { + assert(len > 0, "must be"); + return (int)len; + } else { + return -1; + } } default: // Note: Length functions must return <=0 for invalid bytecodes. diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 45848fb0243..03b47bcd21d 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -67,7 +67,9 @@ void Jfr::on_create_vm_3() { } void Jfr::on_unloading_classes() { - JfrCheckpointManager::on_unloading_classes(); + if (JfrRecorder::is_created() || JfrRecorder::is_started_on_commandline()) { + JfrCheckpointManager::on_unloading_classes(); + } } bool Jfr::is_excluded(Thread* t) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 799d6ef899d..0aed916702e 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -117,16 +117,16 @@ bool JfrCheckpointManager::initialize_early() { assert(_thread_local_mspace == nullptr, "invariant"); _thread_local_mspace = new JfrThreadLocalCheckpointMspace(); if (_thread_local_mspace == nullptr || !_thread_local_mspace->initialize(thread_local_buffer_size, - thread_local_buffer_prealloc_count, - thread_local_buffer_prealloc_count)) { + thread_local_buffer_prealloc_count, + thread_local_buffer_prealloc_count)) { return false; } assert(_virtual_thread_local_mspace == nullptr, "invariant"); _virtual_thread_local_mspace = new JfrThreadLocalCheckpointMspace(); if (_virtual_thread_local_mspace == nullptr || !_virtual_thread_local_mspace->initialize(virtual_thread_local_buffer_size, - JFR_MSPACE_UNLIMITED_CACHE_SIZE, - virtual_thread_local_buffer_prealloc_count)) { + JFR_MSPACE_UNLIMITED_CACHE_SIZE, + virtual_thread_local_buffer_prealloc_count)) { return false; } return true; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp index f99159b3a51..a8ec2fd70f5 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp @@ -55,6 +55,7 @@ struct JfrCheckpointContext { class JfrCheckpointWriter : public JfrCheckpointWriterBase { friend class JfrCheckpointManager; + friend class JfrDeprecationManager; friend class JfrSerializerRegistration; friend class JfrTypeManager; private: diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 94ac0772969..3a86f204e61 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -66,20 +66,38 @@ static bool _class_unload = false; static bool _flushpoint = false; static bool _initial_type_set = true; -static bool current_epoch() { - return _class_unload || _flushpoint; +static inline bool flushpoint() { + return _flushpoint; } -static bool previous_epoch() { +static inline bool unloading() { + return _class_unload; +} + +static inline bool current_epoch() { + return flushpoint() || unloading(); +} + +static inline bool previous_epoch() { return !current_epoch(); } -static bool is_initial_typeset_for_chunk() { - return _initial_type_set && !_class_unload; +template +static inline bool used(const T* ptr) { + assert(ptr != nullptr, "invariant"); + return current_epoch() ? USED_THIS_EPOCH(ptr) : USED_PREVIOUS_EPOCH(ptr); +} + +template +static inline bool not_used(const T* ptr) { + return !used(ptr); } -static bool is_complete() { - return !_artifacts->has_klass_entries() && current_epoch(); +template +static void do_artifact(const T* ptr) { + if (used(ptr)) { + _subsystem_callback->do_artifact(ptr); + } } static traceid mark_symbol(KlassPtr klass, bool leakp) { @@ -94,66 +112,113 @@ static traceid get_bootstrap_name(bool leakp) { return _artifacts->bootstrap_name(leakp); } -static const char* primitive_name(KlassPtr type_array_klass) { - switch (type_array_klass->name()->base()[1]) { - case JVM_SIGNATURE_BOOLEAN: return "boolean"; - case JVM_SIGNATURE_BYTE: return "byte"; - case JVM_SIGNATURE_CHAR: return "char"; - case JVM_SIGNATURE_SHORT: return "short"; - case JVM_SIGNATURE_INT: return "int"; - case JVM_SIGNATURE_LONG: return "long"; - case JVM_SIGNATURE_FLOAT: return "float"; - case JVM_SIGNATURE_DOUBLE: return "double"; - } - assert(false, "invalid type array klass"); - return nullptr; +template +static traceid artifact_id(const T* ptr) { + assert(ptr != nullptr, "invariant"); + return JfrTraceId::load_raw(ptr); } -static Symbol* primitive_symbol(KlassPtr type_array_klass) { - if (type_array_klass == nullptr) { - // void.class - static Symbol* const void_class_name = SymbolTable::probe("void", 4); - assert(void_class_name != nullptr, "invariant"); - return void_class_name; +template +static traceid artifact_tag(const T* ptr, bool leakp) { + assert(ptr != nullptr, "invariant"); + if (leakp) { + if (IS_NOT_LEAKP(ptr)) { + SET_LEAKP(ptr); + } + assert(IS_LEAKP(ptr), "invariant"); + return artifact_id(ptr); } - const char* const primitive_type_str = primitive_name(type_array_klass); - assert(primitive_type_str != nullptr, "invariant"); - Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, (int)strlen(primitive_type_str)); - assert(primitive_type_sym != nullptr, "invariant"); - return primitive_type_sym; + if (not_used(ptr)) { + SET_TRANSIENT(ptr); + } + assert(used(ptr), "invariant"); + return artifact_id(ptr); } -template -static traceid artifact_id(const T* ptr) { - assert(ptr != nullptr, "invariant"); - return JfrTraceId::load_raw(ptr); +static inline CldPtr get_cld(ModPtr mod) { + return mod != nullptr ? mod->loader_data() : nullptr; } -static traceid package_id(KlassPtr klass, bool leakp) { +static ClassLoaderData* get_cld(const Klass* klass) { assert(klass != nullptr, "invariant"); - PkgPtr pkg_entry = klass->package(); - if (pkg_entry == nullptr) { - return 0; + if (klass->is_objArray_klass()) { + klass = ObjArrayKlass::cast(klass)->bottom_klass(); } - if (leakp) { - SET_LEAKP(pkg_entry); + return klass->is_non_strong_hidden() ? nullptr : klass->class_loader_data(); +} + +static inline bool should_do_cld_klass(const Klass* cld_klass, bool leakp) { + return cld_klass != nullptr && _artifacts->should_do_cld_klass(cld_klass, leakp); +} + +static inline bool should_enqueue(const Klass* cld_klass) { + assert(cld_klass != nullptr, "invariant"); + if (previous_epoch()) { + return false; + } + CldPtr cld = get_cld(cld_klass); + return cld != nullptr && !cld->is_unloading(); +} + +static inline KlassPtr get_cld_klass(CldPtr cld, bool leakp) { + if (cld == nullptr) { + return nullptr; } - // package implicitly tagged already - return artifact_id(pkg_entry); + assert(leakp ? IS_LEAKP(cld) : used(cld), "invariant"); + KlassPtr cld_klass = cld->class_loader_klass(); + if (!should_do_cld_klass(cld_klass, leakp)) { + return nullptr; + } + if (should_enqueue(cld_klass)) { + // This will enqueue the klass, which is important for + // reachability when doing clear and reset at rotation. + JfrTraceId::load(cld_klass); + } else { + artifact_tag(cld_klass, leakp); + } + return cld_klass; +} + +static inline ModPtr get_module(PkgPtr pkg) { + return pkg != nullptr ? pkg->module() : nullptr; +} + +static inline PkgPtr get_package(KlassPtr klass) { + return klass != nullptr ? klass->package() : nullptr; +} + +static inline KlassPtr get_module_cld_klass(KlassPtr klass, bool leakp) { + assert(klass != nullptr, "invariant"); + return get_cld_klass(get_cld(get_module(get_package(klass))), leakp); +} + +static traceid cld_id(CldPtr cld, bool leakp) { + assert(cld != nullptr, "invariant"); + return artifact_tag(cld, leakp); } static traceid module_id(PkgPtr pkg, bool leakp) { assert(pkg != nullptr, "invariant"); - ModPtr module_entry = pkg->module(); - if (module_entry == nullptr) { + ModPtr mod = get_module(pkg); + if (mod == nullptr) { return 0; } - if (leakp) { - SET_LEAKP(module_entry); - } else { - SET_TRANSIENT(module_entry); + CldPtr cld = get_cld(mod); + if (cld != nullptr) { + cld_id(cld, leakp); + } + return artifact_tag(mod, leakp); +} + +static traceid package_id(KlassPtr klass, bool leakp) { + assert(klass != nullptr, "invariant"); + PkgPtr pkg = get_package(klass); + if (pkg == nullptr) { + return 0; } - return artifact_id(module_entry); + // Ensure module and its CLD gets tagged. + module_id(pkg, leakp); + return artifact_tag(pkg, leakp); } static traceid method_id(KlassPtr klass, MethodPtr method) { @@ -162,16 +227,6 @@ static traceid method_id(KlassPtr klass, MethodPtr method) { return METHOD_ID(klass, method); } -static traceid cld_id(CldPtr cld, bool leakp) { - assert(cld != nullptr, "invariant"); - if (leakp) { - SET_LEAKP(cld); - } else { - SET_TRANSIENT(cld); - } - return artifact_id(cld); -} - template static s4 get_flags(const T* ptr) { assert(ptr != nullptr, "invariant"); @@ -183,73 +238,203 @@ static u4 get_primitive_flags() { return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC; } -static ClassLoaderData* get_cld(const Klass* klass) { - assert(klass != nullptr, "invariant"); - if (klass->is_objArray_klass()) { - klass = ObjArrayKlass::cast(klass)->bottom_klass(); +class PackageFieldSelector { + public: + typedef PkgPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + return klass->package(); } - if (klass->is_non_strong_hidden()) return nullptr; - return klass->class_loader_data(); -} +}; + +class ModuleFieldSelector { + public: + typedef ModPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + PkgPtr pkg = klass->package(); + return pkg != nullptr ? pkg->module() : nullptr; + } +}; + +class KlassCldFieldSelector { + public: + typedef CldPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + return get_cld(klass); + } +}; + +class ModuleCldFieldSelector { + public: + typedef CldPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + ModPtr mod = ModuleFieldSelector::select(klass); + return mod != nullptr ? mod->loader_data() : nullptr; + } +}; + +template +class SerializePredicate { + bool _class_unload; + public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(T const& value) { + assert(value != nullptr, "invariant"); + return _class_unload ? _artifacts->should_do_unloading_artifact(value) : IS_NOT_SERIALIZED(value); + } +}; + +template <> +class SerializePredicate { + bool _class_unload; +public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(const Klass* klass) { + assert(klass != nullptr, "invariant"); + return _class_unload ? true : IS_NOT_SERIALIZED(klass); + } +}; + +template <> +class SerializePredicate { + bool _class_unload; +public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(const Method* method) { + assert(method != nullptr, "invariant"); + return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method); + } +}; template static void set_serialized(const T* ptr) { assert(ptr != nullptr, "invariant"); - SET_SERIALIZED(ptr); - assert(IS_SERIALIZED(ptr), "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_CLEARED_BIT(ptr); } + SET_SERIALIZED(ptr); + assert(IS_SERIALIZED(ptr), "invariant"); } /* - * In C++03, functions used as template parameters must have external linkage; - * this restriction was removed in C++11. Change back to "static" and - * rename functions when C++11 becomes available. + *********************** Klasses ************************* + * + * When we process a Klass, we need to process its transitive closure. + * + * This includes two branches: + * + * [1] Klass -> CLD -> class_loader_Klass + * [2] Klass -> PackageEntry -> ModuleEntry -> CLD -> class_loader_Klass + * + * A Klass viewed as this closure becomes a node in a binary tree: + * + * Klass + * O + * / \ + * / \ + * [1] O O [2] + * + * We write the Klass and tag the artifacts in its closure (subtree) + * using preorder traversal by recursing the class_loader_Klass(es). * - * The weird naming is an effort to decrease the risk of name clashes. */ -static int write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp) { +static void do_write_klass(JfrCheckpointWriter* writer, CldPtr cld, KlassPtr klass, bool leakp) { assert(writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); assert(klass != nullptr, "invariant"); writer->write(artifact_id(klass)); - ClassLoaderData* cld = get_cld(klass); writer->write(cld != nullptr ? cld_id(cld, leakp) : 0); writer->write(mark_symbol(klass, leakp)); writer->write(package_id(klass, leakp)); writer->write(klass->modifier_flags()); writer->write(klass->is_hidden()); - return 1; + if (!leakp) { + set_serialized(klass); + } +} + +static inline bool should_write_cld_klass(KlassPtr klass, bool leakp) { + return klass != nullptr && (leakp || IS_NOT_SERIALIZED(klass)); +} + +static void write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp, int& elements) { + assert(elements >= 0, "invariant"); + ClassLoaderData* cld = get_cld(klass); + do_write_klass(writer, cld, klass, leakp); + ++elements; + if (cld != nullptr) { + // Write the klass for the direct cld. + KlassPtr cld_klass = get_cld_klass(cld, leakp); + if (should_write_cld_klass(cld_klass, leakp)) { + write_klass(writer, cld_klass, leakp, elements); + } + } + KlassPtr mod_klass = get_module_cld_klass(klass, leakp); + if (should_write_cld_klass(mod_klass, leakp)) { + // Write the klass for the module cld. + write_klass(writer, mod_klass, leakp, elements); + } } +/* + * In C++03, functions used as template parameters must have external linkage; + * this restriction was removed in C++11. Change back to "static" and + * rename functions when C++11 becomes available. + * + * The weird naming is an effort to decrease the risk of name clashes. + */ int write__klass(JfrCheckpointWriter* writer, const void* k) { assert(k != nullptr, "invariant"); - KlassPtr klass = (KlassPtr)k; - set_serialized(klass); - return write_klass(writer, klass, false); + KlassPtr klass = static_cast(k); + int elements = 0; + write_klass(writer, klass, false, elements); + return elements; } int write__klass__leakp(JfrCheckpointWriter* writer, const void* k) { assert(k != nullptr, "invariant"); - KlassPtr klass = (KlassPtr)k; + KlassPtr klass = static_cast(k); CLEAR_LEAKP(klass); - return write_klass(writer, klass, true); + int elements = 0; + write_klass(writer, klass, true, elements); + return elements; } -static bool is_implied(const Klass* klass) { - assert(klass != nullptr, "invariant"); - return klass->is_subclass_of(vmClasses::ClassLoader_klass()) || klass == vmClasses::Object_klass(); -} +static int primitives_count = 9; -static void do_klass(Klass* klass) { - assert(klass != nullptr, "invariant"); - assert(_flushpoint ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass), "invariant"); - assert(_subsystem_callback != nullptr, "invariant"); - _subsystem_callback->do_artifact(klass); +static const char* primitive_name(KlassPtr type_array_klass) { + switch (type_array_klass->name()->base()[1]) { + case JVM_SIGNATURE_BOOLEAN: return "boolean"; + case JVM_SIGNATURE_BYTE: return "byte"; + case JVM_SIGNATURE_CHAR: return "char"; + case JVM_SIGNATURE_SHORT: return "short"; + case JVM_SIGNATURE_INT: return "int"; + case JVM_SIGNATURE_LONG: return "long"; + case JVM_SIGNATURE_FLOAT: return "float"; + case JVM_SIGNATURE_DOUBLE: return "double"; + } + assert(false, "invalid type array klass"); + return nullptr; } +static Symbol* primitive_symbol(KlassPtr type_array_klass) { + if (type_array_klass == nullptr) { + // void.class + static Symbol* const void_class_name = SymbolTable::probe("void", 4); + assert(void_class_name != nullptr, "invariant"); + return void_class_name; + } + const char* const primitive_type_str = primitive_name(type_array_klass); + assert(primitive_type_str != nullptr, "invariant"); + Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, + (int)strlen(primitive_type_str)); + assert(primitive_type_sym != nullptr, "invariant"); + return primitive_type_sym; +} static traceid primitive_id(KlassPtr array_klass) { if (array_klass == nullptr) { @@ -271,148 +456,69 @@ static void write_primitive(JfrCheckpointWriter* writer, KlassPtr type_array_kla writer->write(false); } -static void do_loader_klass(const Klass* klass) { - if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) { - if (_leakp_writer != nullptr) { - SET_LEAKP(klass); - } - SET_TRANSIENT(klass); - _subsystem_callback->do_artifact(klass); - } -} - -static bool register_klass_unload(Klass* klass) { - assert(klass != nullptr, "invariant"); - return JfrKlassUnloading::on_unload(klass); -} - -static void do_unloading_klass(Klass* klass) { - assert(klass != nullptr, "invariant"); - assert(_subsystem_callback != nullptr, "invariant"); - if (register_klass_unload(klass)) { - _subsystem_callback->do_artifact(klass); - do_loader_klass(klass->class_loader_data()->class_loader_klass()); - } -} - -/* - * Abstract klasses are filtered out unconditionally. - * If a klass is not yet initialized, i.e yet to run its - * it is also filtered out so we don't accidentally - * trigger initialization. - */ -static bool is_classloader_klass_allowed(const Klass* k) { - assert(k != nullptr, "invariant"); - return !(k->is_abstract() || k->should_be_initialized()); -} - -static void do_classloaders() { - for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) { - Klass* subk = iter.klass(); - if (is_classloader_klass_allowed(subk)) { - do_loader_klass(subk); - } - } +static bool is_initial_typeset_for_chunk() { + return _initial_type_set && !unloading(); } -static int primitives_count = 9; - // A mirror representing a primitive class (e.g. int.class) has no reified Klass*, // instead it has an associated TypeArrayKlass* (e.g. int[].class). // We can use the TypeArrayKlass* as a proxy for deriving the id of the primitive class. // The exception is the void.class, which has neither a Klass* nor a TypeArrayKlass*. // It will use a reserved constant. static void do_primitives() { - // Only write the primitive classes once per chunk. - if (is_initial_typeset_for_chunk()) { - write_primitive(_writer, Universe::boolArrayKlassObj()); - write_primitive(_writer, Universe::byteArrayKlassObj()); - write_primitive(_writer, Universe::charArrayKlassObj()); - write_primitive(_writer, Universe::shortArrayKlassObj()); - write_primitive(_writer, Universe::intArrayKlassObj()); - write_primitive(_writer, Universe::longArrayKlassObj()); - write_primitive(_writer, Universe::floatArrayKlassObj()); - write_primitive(_writer, Universe::doubleArrayKlassObj()); - write_primitive(_writer, nullptr); // void.class - } + assert(is_initial_typeset_for_chunk(), "invariant"); + write_primitive(_writer, Universe::boolArrayKlassObj()); + write_primitive(_writer, Universe::byteArrayKlassObj()); + write_primitive(_writer, Universe::charArrayKlassObj()); + write_primitive(_writer, Universe::shortArrayKlassObj()); + write_primitive(_writer, Universe::intArrayKlassObj()); + write_primitive(_writer, Universe::longArrayKlassObj()); + write_primitive(_writer, Universe::floatArrayKlassObj()); + write_primitive(_writer, Universe::doubleArrayKlassObj()); + write_primitive(_writer, nullptr); // void.class } -static void do_object() { - SET_TRANSIENT(vmClasses::Object_klass()); - do_klass(vmClasses::Object_klass()); -} - -static void do_klasses() { - if (_class_unload) { - ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass); - return; - } - JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch()); - do_classloaders(); - do_primitives(); - do_object(); -} - -template -static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) { - assert(callback != nullptr, "invariant"); - assert(value != nullptr, "invariant"); - if (USED_PREVIOUS_EPOCH(value)) { - callback->do_artifact(value); - } - if (IS_SERIALIZED(value)) { - CLEAR_SERIALIZED(value); - } - assert(IS_NOT_SERIALIZED(value), "invariant"); -} - -static void do_previous_epoch_klass(JfrArtifactClosure* callback, const Klass* value) { - assert(callback != nullptr, "invariant"); - assert(value != nullptr, "invariant"); - if (USED_PREVIOUS_EPOCH(value)) { - callback->do_artifact(value); +static void do_unloading_klass(Klass* klass) { + assert(klass != nullptr, "invariant"); + assert(_subsystem_callback != nullptr, "invariant"); + if (JfrKlassUnloading::on_unload(klass)) { + _subsystem_callback->do_artifact(klass); } } -static void do_klass_on_clear(Klass* klass) { +static void do_klass(Klass* klass) { assert(klass != nullptr, "invariant"); + assert(used(klass), "invariant"); assert(_subsystem_callback != nullptr, "invariant"); - do_previous_epoch_klass(_subsystem_callback, klass); + _subsystem_callback->do_artifact(klass); } -static void do_loader_klass_on_clear(const Klass* klass) { - if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) { - if (_leakp_writer != nullptr) { - SET_LEAKP(klass); - } - SET_TRANSIENT(klass); - do_previous_epoch_klass(_subsystem_callback, klass); +static void do_klasses() { + if (unloading()) { + ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass); + return; } -} - -static void do_classloaders_on_clear() { - for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) { - Klass* subk = iter.klass(); - if (is_classloader_klass_allowed(subk)) { - do_loader_klass_on_clear(subk); - } + if (is_initial_typeset_for_chunk()) { + // Only write the primitive classes once per chunk. + do_primitives(); } + JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch()); } -static void do_object_on_clear() { - SET_TRANSIENT(vmClasses::Object_klass()); - do_klass_on_clear(vmClasses::Object_klass()); +static void do_klass_on_clear(Klass* klass) { + do_artifact(klass); } static void do_all_klasses() { ClassLoaderDataGraph::classes_do(&do_klass_on_clear); - do_classloaders_on_clear(); - do_object_on_clear(); } +// KlassWriter. typedef SerializePredicate KlassPredicate; typedef JfrPredicatedTypeWriterImplHost KlassWriterImpl; typedef JfrTypeWriterHost KlassWriter; + +// Klass registration. typedef CompositeFunctor KlassWriterRegistration; typedef JfrArtifactCallbackHost KlassCallback; @@ -422,29 +528,31 @@ class LeakPredicate { LeakPredicate(bool class_unload) {} bool operator()(const Klass* klass) { assert(klass != nullptr, "invariant"); - return IS_LEAKP(klass) || is_implied(klass); + return IS_LEAKP(klass); } }; +// KlassWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakKlassPredicate; typedef JfrPredicatedTypeWriterImplHost LeakKlassWriterImpl; typedef JfrTypeWriterHost LeakKlassWriter; +// Composite KlassWriter with registration. typedef CompositeFunctor CompositeKlassWriter; typedef CompositeFunctor CompositeKlassWriterRegistration; typedef JfrArtifactCallbackHost CompositeKlassCallback; -static bool write_klasses() { +static void write_klasses() { assert(!_artifacts->has_klass_entries(), "invariant"); assert(_writer != nullptr, "invariant"); KlassArtifactRegistrator reg(_artifacts); - KlassWriter kw(_writer, _class_unload); + KlassWriter kw(_writer, unloading()); KlassWriterRegistration kwr(&kw, ®); if (_leakp_writer == nullptr) { KlassCallback callback(&_subsystem_callback, &kwr); do_klasses(); } else { - LeakKlassWriter lkw(_leakp_writer, _class_unload); + LeakKlassWriter lkw(_leakp_writer, unloading()); CompositeKlassWriter ckw(&lkw, &kw); CompositeKlassWriterRegistration ckwr(&ckw, ®); CompositeKlassCallback callback(&_subsystem_callback, &ckwr); @@ -455,32 +563,26 @@ static bool write_klasses() { // their count is not automatically incremented. kw.add(primitives_count); } - if (is_complete()) { - return false; - } _artifacts->tally(kw); - return true; } -static bool write_klasses_on_clear() { +static void write_klasses_on_clear() { assert(!_artifacts->has_klass_entries(), "invariant"); assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); KlassArtifactRegistrator reg(_artifacts); - KlassWriter kw(_writer, _class_unload); + KlassWriter kw(_writer, unloading()); KlassWriterRegistration kwr(&kw, ®); - LeakKlassWriter lkw(_leakp_writer, _class_unload); + LeakKlassWriter lkw(_leakp_writer, unloading()); CompositeKlassWriter ckw(&lkw, &kw); CompositeKlassWriterRegistration ckwr(&ckw, ®); CompositeKlassCallback callback(&_subsystem_callback, &ckwr); do_all_klasses(); - if (is_complete()) { - return false; - } _artifacts->tally(kw); - return true; } +/***** Packages *****/ + static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) { assert(writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); @@ -494,98 +596,101 @@ static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) { int write__package(JfrCheckpointWriter* writer, const void* p) { assert(p != nullptr, "invariant"); - PkgPtr pkg = (PkgPtr)p; + PkgPtr pkg = static_cast(p); set_serialized(pkg); return write_package(writer, pkg, false); } int write__package__leakp(JfrCheckpointWriter* writer, const void* p) { assert(p != nullptr, "invariant"); - PkgPtr pkg = (PkgPtr)p; + PkgPtr pkg = static_cast(p); CLEAR_LEAKP(pkg); return write_package(writer, pkg, true); } -static void do_package(PackageEntry* entry) { - do_previous_epoch_artifact(_subsystem_callback, entry); -} - -static void do_packages() { - ClassLoaderDataGraph::packages_do(&do_package); -} - -class PackageFieldSelector { - public: - typedef PkgPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - return klass->package(); - } -}; +// PackageWriter. typedef SerializePredicate PackagePredicate; typedef JfrPredicatedTypeWriterImplHost PackageWriterImpl; typedef JfrTypeWriterHost PackageWriter; -typedef CompositeFunctor > PackageWriterWithClear; +typedef JfrArtifactCallbackHost PackageCallback; + +// PackageWriter used during flush or unloading i.e. the current epoch. typedef KlassToFieldEnvelope KlassPackageWriter; -typedef JfrArtifactCallbackHost PackageCallback; +// PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > PackageWriterWithClear; +typedef JfrArtifactCallbackHost PackageClearCallback; + +// PackageWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakPackagePredicate; typedef JfrPredicatedTypeWriterImplHost LeakPackageWriterImpl; typedef JfrTypeWriterHost LeakPackageWriter; +// Composite PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch. typedef CompositeFunctor CompositePackageWriter; -typedef KlassToFieldEnvelope KlassCompositePackageWriter; -typedef KlassToFieldEnvelope KlassPackageWriterWithClear; typedef CompositeFunctor > CompositePackageWriterWithClear; -typedef JfrArtifactCallbackHost CompositePackageCallback; +typedef JfrArtifactCallbackHost CompositePackageClearCallback; + +static void do_package(PackageEntry* pkg) { + do_artifact(pkg); +} + +static void do_all_packages() { + ClassLoaderDataGraph::packages_do(&do_package); +} + +static void do_all_packages(PackageWriter& pw) { + do_all_packages(); + _artifacts->tally(pw); +} + +static void do_packages(PackageWriter& pw) { + KlassPackageWriter kpw(&pw); + _artifacts->iterate_klasses(kpw); + _artifacts->tally(pw); +} + +static void write_packages_with_leakp(PackageWriter& pw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakPackageWriter lpw(_leakp_writer, unloading()); + CompositePackageWriter cpw(&lpw, &pw); + ClearArtifact clear; + CompositePackageWriterWithClear cpwwc(&cpw, &clear); + CompositePackageClearCallback callback(&_subsystem_callback, &cpwwc); + do_all_packages(pw); +} static void write_packages() { assert(_writer != nullptr, "invariant"); - PackageWriter pw(_writer, _class_unload); - KlassPackageWriter kpw(&pw); + PackageWriter pw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kpw); - _artifacts->tally(pw); + do_packages(pw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kpw); ClearArtifact clear; PackageWriterWithClear pwwc(&pw, &clear); - PackageCallback callback(&_subsystem_callback, &pwwc); - do_packages(); - } else { - LeakPackageWriter lpw(_leakp_writer, _class_unload); - CompositePackageWriter cpw(&lpw, &pw); - KlassCompositePackageWriter kcpw(&cpw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositePackageWriterWithClear cpwwc(&cpw, &clear); - CompositePackageCallback callback(&_subsystem_callback, &cpwwc); - do_packages(); + PackageClearCallback callback(&_subsystem_callback, &pwwc); + do_all_packages(pw); + return; } - _artifacts->tally(pw); + write_packages_with_leakp(pw); } static void write_packages_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - PackageWriter pw(_writer, _class_unload); - KlassPackageWriter kpw(&pw); - LeakPackageWriter lpw(_leakp_writer, _class_unload); - CompositePackageWriter cpw(&lpw, &pw); - KlassCompositePackageWriter kcpw(&cpw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositePackageWriterWithClear cpwwc(&cpw, &clear); - CompositePackageCallback callback(&_subsystem_callback, &cpwwc); - do_packages(); - _artifacts->tally(pw); + PackageWriter pw(_writer, unloading()); + write_packages_with_leakp(pw); } +/***** Modules *****/ + static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) { assert(mod != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); @@ -599,99 +704,101 @@ static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) { int write__module(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - ModPtr mod = (ModPtr)m; + ModPtr mod = static_cast(m); set_serialized(mod); return write_module(writer, mod, false); } int write__module__leakp(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - ModPtr mod = (ModPtr)m; + ModPtr mod = static_cast(m); CLEAR_LEAKP(mod); return write_module(writer, mod, true); } -static void do_module(ModuleEntry* entry) { - do_previous_epoch_artifact(_subsystem_callback, entry); -} - -static void do_modules() { - ClassLoaderDataGraph::modules_do(&do_module); -} - -class ModuleFieldSelector { - public: - typedef ModPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - PkgPtr pkg = klass->package(); - return pkg != nullptr ? pkg->module() : nullptr; - } -}; - +// ModuleWriter. typedef SerializePredicate ModulePredicate; typedef JfrPredicatedTypeWriterImplHost ModuleWriterImpl; typedef JfrTypeWriterHost ModuleWriter; -typedef CompositeFunctor > ModuleWriterWithClear; -typedef JfrArtifactCallbackHost ModuleCallback; +typedef JfrArtifactCallbackHost ModuleCallback; + +// ModuleWriter used during flush or unloading i.e. the current epoch. typedef KlassToFieldEnvelope KlassModuleWriter; +// ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > ModuleWriterWithClear; +typedef JfrArtifactCallbackHost ModuleClearCallback; + +// ModuleWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakModulePredicate; typedef JfrPredicatedTypeWriterImplHost LeakModuleWriterImpl; typedef JfrTypeWriterHost LeakModuleWriter; +// Composite ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch. typedef CompositeFunctor CompositeModuleWriter; -typedef KlassToFieldEnvelope KlassCompositeModuleWriter; typedef CompositeFunctor > CompositeModuleWriterWithClear; -typedef JfrArtifactCallbackHost CompositeModuleCallback; +typedef JfrArtifactCallbackHost CompositeModuleClearCallback; + +static void do_module(ModuleEntry* mod) { + do_artifact(mod); +} + +static void do_all_modules() { + ClassLoaderDataGraph::modules_do(&do_module); +} + +static void do_all_modules(ModuleWriter& mw) { + do_all_modules(); + _artifacts->tally(mw); +} + +static void do_modules(ModuleWriter& mw) { + KlassModuleWriter kmw(&mw); + _artifacts->iterate_klasses(kmw); + _artifacts->tally(mw); +} + +static void write_modules_with_leakp(ModuleWriter& mw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakModuleWriter lmw(_leakp_writer, unloading()); + CompositeModuleWriter cmw(&lmw, &mw); + ClearArtifact clear; + CompositeModuleWriterWithClear cmwwc(&cmw, &clear); + CompositeModuleClearCallback callback(&_subsystem_callback, &cmwwc); + do_all_modules(mw); +} static void write_modules() { assert(_writer != nullptr, "invariant"); - ModuleWriter mw(_writer, _class_unload); - KlassModuleWriter kmw(&mw); + ModuleWriter mw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kmw); - _artifacts->tally(mw); + do_modules(mw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kmw); ClearArtifact clear; ModuleWriterWithClear mwwc(&mw, &clear); - ModuleCallback callback(&_subsystem_callback, &mwwc); - do_modules(); - } else { - LeakModuleWriter lmw(_leakp_writer, _class_unload); - CompositeModuleWriter cmw(&lmw, &mw); - KlassCompositeModuleWriter kcpw(&cmw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositeModuleWriterWithClear cmwwc(&cmw, &clear); - CompositeModuleCallback callback(&_subsystem_callback, &cmwwc); - do_modules(); + ModuleClearCallback callback(&_subsystem_callback, &mwwc); + do_all_modules(mw); + return; } - _artifacts->tally(mw); + write_modules_with_leakp(mw); } static void write_modules_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - ModuleWriter mw(_writer, _class_unload); - KlassModuleWriter kmw(&mw); - LeakModuleWriter lmw(_leakp_writer, _class_unload); - CompositeModuleWriter cmw(&lmw, &mw); - KlassCompositeModuleWriter kcpw(&cmw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositeModuleWriterWithClear cmwwc(&cmw, &clear); - CompositeModuleCallback callback(&_subsystem_callback, &cmwwc); - do_modules(); - _artifacts->tally(mw); + ModuleWriter mw(_writer, unloading()); + write_modules_with_leakp(mw); } -static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { +/***** ClassLoaderData - CLD *****/ + +static int write_cld(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { assert(cld != nullptr, "invariant"); // class loader type const Klass* class_loader_klass = cld->class_loader_klass(); @@ -701,7 +808,7 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp writer->write((traceid)0); // class loader type id (absence of) writer->write(get_bootstrap_name(leakp)); // maps to synthetic name -> "bootstrap" } else { - assert(_class_unload ? true : IS_SERIALIZED(class_loader_klass), "invariant"); + assert(IS_SERIALIZED(class_loader_klass), "invariant"); writer->write(artifact_id(cld)); // class loader instance id writer->write(artifact_id(class_loader_klass)); // class loader type id writer->write(mark_symbol(cld->name(), leakp)); // class loader instance name @@ -709,146 +816,127 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp return 1; } -int write__classloader(JfrCheckpointWriter* writer, const void* c) { +int write__cld(JfrCheckpointWriter* writer, const void* c) { assert(c != nullptr, "invariant"); - CldPtr cld = (CldPtr)c; + CldPtr cld = static_cast(c); set_serialized(cld); - return write_classloader(writer, cld, false); + return write_cld(writer, cld, false); } -int write__classloader__leakp(JfrCheckpointWriter* writer, const void* c) { +int write__cld__leakp(JfrCheckpointWriter* writer, const void* c) { assert(c != nullptr, "invariant"); - CldPtr cld = (CldPtr)c; + CldPtr cld = static_cast(c); CLEAR_LEAKP(cld); - return write_classloader(writer, cld, true); + return write_cld(writer, cld, true); } -static void do_class_loader_data(ClassLoaderData* cld) { - do_previous_epoch_artifact(_subsystem_callback, cld); -} +// CldWriter. +typedef SerializePredicate CldPredicate; +typedef JfrPredicatedTypeWriterImplHost CldWriterImpl; +typedef JfrTypeWriterHost CldWriter; +typedef JfrArtifactCallbackHost CldCallback; -class KlassCldFieldSelector { - public: - typedef CldPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - return get_cld(klass); - } -}; +// CldWriter used during flush or unloading i.e. the current epoch. +typedef KlassToFieldEnvelope KlassCldWriter; +typedef KlassToFieldEnvelope ModuleCldWriter; +typedef CompositeFunctor KlassAndModuleCldWriter; -class ModuleCldFieldSelector { -public: - typedef CldPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - ModPtr mod = ModuleFieldSelector::select(klass); - return mod != nullptr ? mod->loader_data() : nullptr; - } -}; +// CldWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > CldWriterWithClear; +typedef JfrArtifactCallbackHost CldClearCallback; + +// CldWriter for leakp. Only used during start or rotation, i.e. the previous epoch. +typedef LeakPredicate LeakCldPredicate; +typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl; +typedef JfrTypeWriterHost LeakCldWriter; + +// Composite CldWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor CompositeCldWriter; +typedef CompositeFunctor > CompositeCldWriterWithClear; +typedef JfrArtifactCallbackHost CompositeCldClearCallback; class CLDCallback : public CLDClosure { public: - CLDCallback() {} void do_cld(ClassLoaderData* cld) { assert(cld != nullptr, "invariant"); - if (cld->has_class_mirror_holder()) { - return; + if (!cld->has_class_mirror_holder()) { + do_artifact(cld); } - do_class_loader_data(cld); } }; -static void do_class_loaders() { +static void do_all_clds() { CLDCallback cld_cb; ClassLoaderDataGraph::loaded_cld_do(&cld_cb); } -typedef SerializePredicate CldPredicate; -typedef JfrPredicatedTypeWriterImplHost CldWriterImpl; -typedef JfrTypeWriterHost CldWriter; -typedef CompositeFunctor > CldWriterWithClear; -typedef JfrArtifactCallbackHost CldCallback; -typedef KlassToFieldEnvelope KlassCldWriter; -typedef KlassToFieldEnvelope ModuleCldWriter; -typedef CompositeFunctor KlassAndModuleCldWriter; - -typedef LeakPredicate LeakCldPredicate; -typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl; -typedef JfrTypeWriterHost LeakCldWriter; - -typedef CompositeFunctor CompositeCldWriter; -typedef KlassToFieldEnvelope KlassCompositeCldWriter; -typedef KlassToFieldEnvelope ModuleCompositeCldWriter; -typedef CompositeFunctor KlassAndModuleCompositeCldWriter; -typedef CompositeFunctor > CompositeCldWriterWithClear; -typedef JfrArtifactCallbackHost CompositeCldCallback; +static void do_all_clds(CldWriter& cldw) { + do_all_clds(); + _artifacts->tally(cldw); +} -static void write_classloaders() { - assert(_writer != nullptr, "invariant"); - CldWriter cldw(_writer, _class_unload); +static void do_clds(CldWriter& cldw) { KlassCldWriter kcw(&cldw); ModuleCldWriter mcw(&cldw); KlassAndModuleCldWriter kmcw(&kcw, &mcw); + _artifacts->iterate_klasses(kmcw); + _artifacts->tally(cldw); +} + +static void write_clds_with_leakp(CldWriter& cldw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakCldWriter lcldw(_leakp_writer, unloading()); + CompositeCldWriter ccldw(&lcldw, &cldw); + ClearArtifact clear; + CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); + CompositeCldClearCallback callback(&_subsystem_callback, &ccldwwc); + do_all_clds(cldw); +} + +static void write_clds() { + assert(_writer != nullptr, "invariant"); + CldWriter cldw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kmcw); - _artifacts->tally(cldw); + do_clds(cldw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kmcw); ClearArtifact clear; CldWriterWithClear cldwwc(&cldw, &clear); - CldCallback callback(&_subsystem_callback, &cldwwc); - do_class_loaders(); - } else { - LeakCldWriter lcldw(_leakp_writer, _class_unload); - CompositeCldWriter ccldw(&lcldw, &cldw); - KlassCompositeCldWriter kccldw(&ccldw); - ModuleCompositeCldWriter mccldw(&ccldw); - KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw); - _artifacts->iterate_klasses(kmccldw); - ClearArtifact clear; - CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); - CompositeCldCallback callback(&_subsystem_callback, &ccldwwc); - do_class_loaders(); + CldClearCallback callback(&_subsystem_callback, &cldwwc); + do_all_clds(cldw); + return; } - _artifacts->tally(cldw); + write_clds_with_leakp(cldw); } -static void write_classloaders_on_clear() { +static void write_clds_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); - CldWriter cldw(_writer, _class_unload); - KlassCldWriter kcw(&cldw); - ModuleCldWriter mcw(&cldw); - KlassAndModuleCldWriter kmcw(&kcw, &mcw); - LeakCldWriter lcldw(_leakp_writer, _class_unload); - CompositeCldWriter ccldw(&lcldw, &cldw); - KlassCompositeCldWriter kccldw(&ccldw); - ModuleCompositeCldWriter mccldw(&ccldw); - KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw); - _artifacts->iterate_klasses(kmccldw); - ClearArtifact clear; - CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); - CompositeCldCallback callback(&_subsystem_callback, &ccldwwc); - do_class_loaders(); - _artifacts->tally(cldw); + assert(previous_epoch(), "invariant"); + CldWriter cldw(_writer, unloading()); + write_clds_with_leakp(cldw); } -static u1 get_visibility(MethodPtr method) { - assert(method != nullptr, "invariant"); - return const_cast(method)->is_hidden() ? (u1)1 : (u1)0; -} +/***** Methods *****/ template <> void set_serialized(MethodPtr method) { assert(method != nullptr, "invariant"); - SET_METHOD_SERIALIZED(method); - assert(METHOD_IS_SERIALIZED(method), "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method); } + assert(unloading() ? true : METHOD_IS_NOT_SERIALIZED(method), "invariant"); + SET_METHOD_SERIALIZED(method); + assert(METHOD_IS_SERIALIZED(method), "invariant"); +} + +static inline u1 get_visibility(MethodPtr method) { + assert(method != nullptr, "invariant"); + return const_cast(method)->is_hidden() ? (u1)1 : (u1)0; } static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leakp) { @@ -857,58 +945,36 @@ static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leak assert(_artifacts != nullptr, "invariant"); KlassPtr klass = method->method_holder(); assert(klass != nullptr, "invariant"); + assert(used(klass), "invariant"); + assert(IS_SERIALIZED(klass), "invariant"); writer->write(method_id(klass, method)); writer->write(artifact_id(klass)); writer->write(mark_symbol(method->name(), leakp)); writer->write(mark_symbol(method->signature(), leakp)); - writer->write((u2)get_flags(method)); + writer->write(static_cast(get_flags(method))); writer->write(get_visibility(method)); return 1; } int write__method(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - MethodPtr method = (MethodPtr)m; + MethodPtr method = static_cast(m); set_serialized(method); return write_method(writer, method, false); } int write__method__leakp(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - MethodPtr method = (MethodPtr)m; + MethodPtr method = static_cast(m); CLEAR_LEAKP_METHOD(method); return write_method(writer, method, true); } - -class BitMapFilter { - ResourceBitMap _bitmap; - public: - explicit BitMapFilter(int length = 0) : _bitmap((size_t)length) {} - bool operator()(size_t idx) { - if (_bitmap.size() == 0) { - return true; - } - if (_bitmap.at(idx)) { - return false; - } - _bitmap.set_bit(idx); - return true; - } -}; - -class AlwaysTrue { - public: - explicit AlwaysTrue(int length = 0) {} - bool operator()(size_t idx) { - return true; - } -}; - -template +template class MethodIteratorHost { private: MethodCallback _method_cb; KlassCallback _klass_cb; + KlassUsedPredicate _klass_used_predicate; MethodUsedPredicate _method_used_predicate; MethodFlagPredicate _method_flag_predicate; public: @@ -918,6 +984,7 @@ class MethodIteratorHost { bool skip_header = false) : _method_cb(writer, class_unload, skip_header), _klass_cb(writer, class_unload, skip_header), + _klass_used_predicate(current_epoch), _method_used_predicate(current_epoch), _method_flag_predicate(current_epoch) {} @@ -937,7 +1004,7 @@ class MethodIteratorHost { ik = ik->previous_versions(); } } - return _klass_cb(klass); + return _klass_used_predicate(klass) ? _klass_cb(klass) : true; } int count() const { return _method_cb.count(); } @@ -964,37 +1031,42 @@ typedef SerializePredicate MethodPredicate; typedef JfrPredicatedTypeWriterImplHost MethodWriterImplTarget; typedef Wrapper KlassCallbackStub; typedef JfrTypeWriterHost MethodWriterImpl; -typedef MethodIteratorHost MethodWriter; +typedef MethodIteratorHost MethodWriter; typedef LeakPredicate LeakMethodPredicate; typedef JfrPredicatedTypeWriterImplHost LeakMethodWriterImplTarget; typedef JfrTypeWriterHost LeakMethodWriterImpl; -typedef MethodIteratorHost LeakMethodWriter; -typedef MethodIteratorHost LeakMethodWriter; +typedef MethodIteratorHost LeakMethodWriter; +typedef MethodIteratorHost LeakMethodWriter; typedef CompositeFunctor CompositeMethodWriter; +static void write_methods_with_leakp(MethodWriter& mw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakMethodWriter lpmw(_leakp_writer, current_epoch(), unloading()); + CompositeMethodWriter cmw(&lpmw, &mw); + _artifacts->iterate_klasses(cmw); + _artifacts->tally(mw); +} + static void write_methods() { assert(_writer != nullptr, "invariant"); - MethodWriter mw(_writer, current_epoch(), _class_unload); + MethodWriter mw(_writer, current_epoch(), unloading()); if (_leakp_writer == nullptr) { _artifacts->iterate_klasses(mw); - } else { - LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload); - CompositeMethodWriter cmw(&lpmw, &mw); - _artifacts->iterate_klasses(cmw); + _artifacts->tally(mw); + return; } - _artifacts->tally(mw); + write_methods_with_leakp(mw); } static void write_methods_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - MethodWriter mw(_writer, current_epoch(), _class_unload); - LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload); - CompositeMethodWriter cmw(&lpmw, &mw); - _artifacts->iterate_klasses(cmw); - _artifacts->tally(mw); + MethodWriter mw(_writer, current_epoch(), unloading()); + write_methods_with_leakp(mw); } template <> @@ -1022,14 +1094,14 @@ static int write_symbol(JfrCheckpointWriter* writer, SymbolEntryPtr entry, bool int write__symbol(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - SymbolEntryPtr entry = (SymbolEntryPtr)e; + SymbolEntryPtr entry = static_cast(e); set_serialized(entry); return write_symbol(writer, entry, false); } int write__symbol__leakp(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - SymbolEntryPtr entry = (SymbolEntryPtr)e; + SymbolEntryPtr entry = static_cast(e); return write_symbol(writer, entry, true); } @@ -1043,14 +1115,14 @@ static int write_string(JfrCheckpointWriter* writer, StringEntryPtr entry, bool int write__string(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - StringEntryPtr entry = (StringEntryPtr)e; + StringEntryPtr entry = static_cast(e); set_serialized(entry); return write_string(writer, entry, false); } int write__string__leakp(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - StringEntryPtr entry = (StringEntryPtr)e; + StringEntryPtr entry = static_cast(e); return write_string(writer, entry, true); } @@ -1071,30 +1143,15 @@ typedef JfrTypeWriterHost LeakStringEntr typedef CompositeFunctor CompositeStringWriter; static void write_symbols_with_leakp() { - assert(_leakp_writer != nullptr, "invariant"); - SymbolEntryWriter sw(_writer, _class_unload); - LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload); - CompositeSymbolWriter csw(&lsw, &sw); - _artifacts->iterate_symbols(csw); - StringEntryWriter sew(_writer, _class_unload, true); // skip header - LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header - CompositeStringWriter csew(&lsew, &sew); - _artifacts->iterate_strings(csew); - sw.add(sew.count()); - lsw.add(lsew.count()); - _artifacts->tally(sw); -} - -static void write_symbols_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - SymbolEntryWriter sw(_writer, _class_unload); - LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload); + SymbolEntryWriter sw(_writer, unloading()); + LeakSymbolEntryWriter lsw(_leakp_writer, unloading()); CompositeSymbolWriter csw(&lsw, &sw); _artifacts->iterate_symbols(csw); - StringEntryWriter sew(_writer, _class_unload, true); // skip header - LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header + StringEntryWriter sew(_writer, unloading(), true); // skip header + LeakStringEntryWriter lsew(_leakp_writer, unloading(), true); // skip header CompositeStringWriter csew(&lsew, &sew); _artifacts->iterate_strings(csew); sw.add(sew.count()); @@ -1108,17 +1165,24 @@ static void write_symbols() { write_symbols_with_leakp(); return; } - SymbolEntryWriter sw(_writer, _class_unload); + SymbolEntryWriter sw(_writer, unloading()); _artifacts->iterate_symbols(sw); - StringEntryWriter sew(_writer, _class_unload, true); // skip header + StringEntryWriter sew(_writer, unloading(), true); // skip header _artifacts->iterate_strings(sew); sw.add(sew.count()); _artifacts->tally(sw); } +static void write_symbols_on_clear() { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + write_symbols_with_leakp(); +} + typedef Wrapper ClearKlassBits; typedef Wrapper ClearMethodFlag; -typedef MethodIteratorHost ClearKlassAndMethods; +typedef MethodIteratorHost ClearKlassAndMethods; static void clear_klasses_and_methods() { ClearKlassAndMethods clear(_writer); @@ -1165,19 +1229,17 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l setup(writer, leakp_writer, class_unload, flushpoint); // write order is important because an individual write step // might tag an artifact to be written in a subsequent step - if (!write_klasses()) { - return 0; - } + write_klasses(); write_packages(); write_modules(); - write_classloaders(); + write_clds(); write_methods(); write_symbols(); return teardown(); } /** - * Clear all tags from the previous epoch. + * Clear all tags from the previous epoch. Reset support structures. */ void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) { ResourceMark rm; @@ -1185,7 +1247,7 @@ void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_w write_klasses_on_clear(); write_packages_on_clear(); write_modules_on_clear(); - write_classloaders_on_clear(); + write_clds_on_clear(); write_methods_on_clear(); write_symbols_on_clear(); teardown(); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index 0876281d53f..883821f853c 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -32,7 +32,8 @@ JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_table(nullptr), _klass_list(nullptr), - _total_count(0) { + _total_count(0), + _class_unload(class_unload) { initialize(class_unload); assert(_klass_list != nullptr, "invariant"); } @@ -41,6 +42,7 @@ static const size_t initial_klass_list_size = 256; const int initial_klass_loader_set_size = 64; void JfrArtifactSet::initialize(bool class_unload) { + _class_unload = class_unload; if (_symbol_table == nullptr) { _symbol_table = JfrSymbolTable::create(); assert(_symbol_table != nullptr, "invariant"); @@ -51,6 +53,11 @@ void JfrArtifactSet::initialize(bool class_unload) { // resource allocation _klass_list = new GrowableArray(initial_klass_list_size); _klass_loader_set = new GrowableArray(initial_klass_loader_set_size); + _klass_loader_leakp_set = new GrowableArray(initial_klass_loader_set_size); + + if (class_unload) { + _unloading_set = new GrowableArray(initial_klass_list_size); + } } void JfrArtifactSet::clear() { @@ -97,10 +104,27 @@ int JfrArtifactSet::entries() const { return _klass_list->length(); } -bool JfrArtifactSet::should_do_loader_klass(const Klass* k) { +static inline bool not_in_set(GrowableArray* set, const Klass* k) { + assert(set != nullptr, "invariant"); + assert(k != nullptr, "invariant"); + return !JfrMutablePredicate::test(set, k); +} + +bool JfrArtifactSet::should_do_cld_klass(const Klass* k, bool leakp) { assert(k != nullptr, "invariant"); assert(_klass_loader_set != nullptr, "invariant"); - return !JfrMutablePredicate::test(_klass_loader_set, k); + assert(_klass_loader_leakp_set != nullptr, "invariant"); + return not_in_set(leakp ? _klass_loader_leakp_set : _klass_loader_set, k); +} + +bool JfrArtifactSet::should_do_unloading_artifact(const void* ptr) { + assert(ptr != nullptr, "invariant"); + assert(_class_unload, "invariant"); + assert(_unloading_set != nullptr, "invariant"); + // The incoming pointers are of all kinds of different types. + // However, we are only interested in set membership. + // Treat them uniformly as const Klass* for simplicity and code reuse. + return not_in_set(_unloading_set, static_cast(ptr)); } void JfrArtifactSet::register_klass(const Klass* k) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index b0c2d989de5..24424fdef3a 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -114,28 +114,6 @@ class ClearArtifact { } }; -template -class SerializePredicate { - bool _class_unload; - public: - SerializePredicate(bool class_unload) : _class_unload(class_unload) {} - bool operator()(T const& value) { - assert(value != nullptr, "invariant"); - return _class_unload ? true : IS_NOT_SERIALIZED(value); - } -}; - -template <> -class SerializePredicate { - bool _class_unload; - public: - SerializePredicate(bool class_unload) : _class_unload(class_unload) {} - bool operator()(const Method* method) { - assert(method != nullptr, "invariant"); - return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method); - } -}; - template class SymbolPredicate { bool _class_unload; @@ -150,11 +128,23 @@ class SymbolPredicate { } }; +class KlassUsedPredicate { + bool _current_epoch; +public: + KlassUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} + bool operator()(const Klass* klass) { + return _current_epoch ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass); + } +}; + class MethodUsedPredicate { bool _current_epoch; public: MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} bool operator()(const Klass* klass) { + if (!klass->is_instance_klass()) { + return false; + } return _current_epoch ? METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_PREVIOUS_EPOCH(klass); } }; @@ -210,7 +200,10 @@ class JfrArtifactSet : public JfrCHeapObj { JfrSymbolTable* _symbol_table; GrowableArray* _klass_list; GrowableArray* _klass_loader_set; + GrowableArray* _klass_loader_leakp_set; + GrowableArray* _unloading_set; size_t _total_count; + bool _class_unload; public: JfrArtifactSet(bool class_unload); @@ -235,14 +228,20 @@ class JfrArtifactSet : public JfrCHeapObj { int entries() const; size_t total_count() const; void register_klass(const Klass* k); - bool should_do_loader_klass(const Klass* k); + bool should_do_cld_klass(const Klass* k, bool leakp); + bool should_do_unloading_artifact(const void* ptr); void increment_checkpoint_id(); template void iterate_klasses(Functor& functor) const { for (int i = 0; i < _klass_list->length(); ++i) { if (!functor(_klass_list->at(i))) { - break; + return; + } + } + for (int i = 0; i < _klass_loader_set->length(); ++i) { + if (!functor(_klass_loader_set->at(i))) { + return; } } } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp index e5b9a33ef56..13853e14a13 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp @@ -33,6 +33,7 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp" +#include "jfr/support/jfrKlassExtension.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" #include "runtime/javaThread.hpp" @@ -66,10 +67,14 @@ inline traceid set_used_and_get(const T* type) { return TRACE_ID(type); } +// We set the 'method_and_class' bits to have a consistent +// bit pattern set always. This is because the tag is non-atomic, +// hence, we always need the same bit pattern in an epoch to avoid losing information. inline void JfrTraceIdLoadBarrier::load_barrier(const Klass* klass) { - SET_USED_THIS_EPOCH(klass); - enqueue(klass); - JfrTraceIdEpoch::set_changed_tag_state(); + SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass); + assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant"); + enqueue(klass); + JfrTraceIdEpoch::set_changed_tag_state(); } inline traceid JfrTraceIdLoadBarrier::load(const Klass* klass) { @@ -113,26 +118,36 @@ inline traceid JfrTraceIdLoadBarrier::load_no_enqueue(const Klass* klass, const return (METHOD_ID(klass, method)); } -inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) { - return set_used_and_get(module); -} - -inline traceid JfrTraceIdLoadBarrier::load(const PackageEntry* package) { - return set_used_and_get(package); -} - inline traceid JfrTraceIdLoadBarrier::load(const ClassLoaderData* cld) { assert(cld != nullptr, "invariant"); if (cld->has_class_mirror_holder()) { return 0; } const Klass* const class_loader_klass = cld->class_loader_klass(); - if (class_loader_klass != nullptr && should_tag(class_loader_klass)) { - load_barrier(class_loader_klass); + if (class_loader_klass != nullptr) { + load(class_loader_klass); } return set_used_and_get(cld); } +inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) { + assert(module != nullptr, "invariant"); + const ClassLoaderData* cld = module->loader_data(); + if (cld != nullptr) { + load(cld); + } + return set_used_and_get(module); +} + +inline traceid JfrTraceIdLoadBarrier::load(const PackageEntry* package) { + assert(package != nullptr, "invariant"); + const ModuleEntry* const module_entry = package->module(); + if (module_entry != nullptr) { + load(module_entry); + } + return set_used_and_get(package); +} + inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Method* method) { assert(klass != nullptr, "invariant"); assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant"); diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index 40c3d7a8c4f..cc460f8c2aa 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -86,9 +86,6 @@ bool JfrRecorder::create_oop_storages() { return ObjectSampler::create_oop_storage(); } -// Subsystem -static JfrCheckpointManager* _checkpoint_manager = nullptr; - bool JfrRecorder::on_create_vm_1() { if (!is_disabled()) { if (FlightRecorder || is_started_on_commandline()) { @@ -99,9 +96,10 @@ bool JfrRecorder::on_create_vm_1() { return false; } - _checkpoint_manager = JfrCheckpointManager::create(); - if (_checkpoint_manager == nullptr || !_checkpoint_manager->initialize_early()) { - return false; + if (is_started_on_commandline()) { + if (!create_checkpoint_manager()) { + return false; + } } // fast time initialization @@ -292,7 +290,7 @@ bool JfrRecorder::create_components() { if (!create_storage()) { return false; } - if (!create_checkpoint_manager()) { + if (!initialize_checkpoint_manager()) { return false; } if (!create_stacktrace_repository()) { @@ -321,6 +319,7 @@ static JfrStackTraceRepository* _stack_trace_repository; static JfrStringPool* _stringpool = nullptr; static JfrOSInterface* _os_interface = nullptr; static JfrThreadSampling* _thread_sampling = nullptr; +static JfrCheckpointManager* _checkpoint_manager = nullptr; bool JfrRecorder::create_java_event_writer() { return JfrJavaEventWriter::initialize(); @@ -357,6 +356,17 @@ bool JfrRecorder::create_storage() { } bool JfrRecorder::create_checkpoint_manager() { + assert(_checkpoint_manager == nullptr, "invariant"); + _checkpoint_manager = JfrCheckpointManager::create(); + return _checkpoint_manager != nullptr && _checkpoint_manager->initialize_early(); +} + +bool JfrRecorder::initialize_checkpoint_manager() { + if (_checkpoint_manager == nullptr) { + if (!create_checkpoint_manager()) { + return false; + } + } assert(_checkpoint_manager != nullptr, "invariant"); assert(_repository != nullptr, "invariant"); return _checkpoint_manager->initialize(&_repository->chunkwriter()); diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp index 3e2541fad98..9f4969b0187 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp @@ -42,6 +42,7 @@ class JfrRecorder : public JfrCHeapObj { static bool on_create_vm_2(); static bool on_create_vm_3(); static bool create_checkpoint_manager(); + static bool initialize_checkpoint_manager(); static bool create_chunk_repository(); static bool create_java_event_writer(); static bool create_jvmti_agent(); diff --git a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp index 09a452caaa5..49ced300e55 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp @@ -626,8 +626,8 @@ inline bool ReinitializeAllReleaseRetiredOp::process(typename const bool retired = node->retired(); node->reinitialize(); assert(node->empty(), "invariant"); - assert(!node->retired(), "invariant"); if (retired) { + assert(!node->retired(), "invariant"); _prev = _list.excise(_prev, node); node->release(); mspace_release(node, _mspace); diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp index a36b85dbb7e..5f5c87d239c 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp @@ -371,8 +371,10 @@ void JfrDeprecationManager::write_edges(JfrChunkWriter& cw, Thread* thread, bool void JfrDeprecationManager::on_type_set(JfrCheckpointWriter& writer, JfrChunkWriter* cw, Thread* thread) { assert(_pending_list.is_empty(), "invariant"); - if (writer.has_data() && _pending_head != nullptr) { + if (_pending_head != nullptr) { save_type_set_blob(writer); + } else { + writer.cancel(); } if (cw != nullptr) { write_edges(*cw, thread); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 5fdc70d7bc7..bac9a786fd9 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -220,6 +220,7 @@ nonstatic_field(JavaThread, _lock_stack, LockStack) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \ + JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ \ nonstatic_field(LockStack, _top, uint32_t) \ \ diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 34f982d9f40..89d5ccbb168 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -395,7 +395,8 @@ class Method : public Metadata { void remove_unshareable_flags() NOT_CDS_RETURN; // the number of argument reg slots that the compiled method uses on the stack. - int num_stack_arg_slots() const { return constMethod()->num_stack_arg_slots(); } + int num_stack_arg_slots(bool rounded = true) const { + return rounded ? align_up(constMethod()->num_stack_arg_slots(), 2) : constMethod()->num_stack_arg_slots(); } virtual void metaspace_pointers_do(MetaspaceClosure* iter); virtual MetaspaceObj::Type type() const { return MethodType; } diff --git a/src/hotspot/share/oops/stackChunkOop.hpp b/src/hotspot/share/oops/stackChunkOop.hpp index 36b06ecd324..abfe47ad3f1 100644 --- a/src/hotspot/share/oops/stackChunkOop.hpp +++ b/src/hotspot/share/oops/stackChunkOop.hpp @@ -155,7 +155,7 @@ class stackChunkOopDesc : public instanceOopDesc { inline void* gc_data() const; inline BitMapView bitmap() const; - inline BitMap::idx_t bit_index_for(intptr_t* p) const; + inline BitMap::idx_t bit_index_for(address p) const; inline intptr_t* address_for_bit(BitMap::idx_t index) const; template inline BitMap::idx_t bit_index_for(OopT* p) const; template inline OopT* address_for_bit(BitMap::idx_t index) const; diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp index e1993207266..c7590861032 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -256,12 +256,13 @@ inline BitMapView stackChunkOopDesc::bitmap() const { return bitmap; } -inline BitMap::idx_t stackChunkOopDesc::bit_index_for(intptr_t* p) const { +inline BitMap::idx_t stackChunkOopDesc::bit_index_for(address p) const { return UseCompressedOops ? bit_index_for((narrowOop*)p) : bit_index_for((oop*)p); } template inline BitMap::idx_t stackChunkOopDesc::bit_index_for(OopT* p) const { + assert(is_aligned(p, alignof(OopT)), "should be aligned: " PTR_FORMAT, p2i(p)); assert(p >= (OopT*)start_address(), "Address not in chunk"); return p - (OopT*)start_address(); } diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 5e9dfcacafd..ba383a679e1 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -822,6 +822,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_notifyJvmtiVThreadMount: case vmIntrinsics::_notifyJvmtiVThreadUnmount: case vmIntrinsics::_notifyJvmtiVThreadHideFrames: + case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: #endif break; diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 514155c6af8..f133e688cc5 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -4006,6 +4006,13 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, if (n == nullptr) { continue; } + } else if (n->is_CallLeaf()) { + // Runtime calls with narrow memory input (no MergeMem node) + // get the memory projection + n = n->as_Call()->proj_out_or_null(TypeFunc::Memory); + if (n == nullptr) { + continue; + } } else if (n->Opcode() == Op_StrCompressedCopy || n->Opcode() == Op_EncodeISOArray) { // get the memory projection @@ -4048,7 +4055,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, continue; } memnode_worklist.append_if_missing(use); - } else if (use->is_MemBar()) { + } else if (use->is_MemBar() || use->is_CallLeaf()) { if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge memnode_worklist.append_if_missing(use); } diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 2751e891262..230a928b0c1 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -1872,6 +1872,46 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { // then we are guaranteed to fail, so just start interpreting there. // We 'expand' the top 3 range checks to include all post-dominating // checks. + // + // Example: + // a[i+x] // (1) 1 < x < 6 + // a[i+3] // (2) + // a[i+4] // (3) + // a[i+6] // max = max of all constants + // a[i+2] + // a[i+1] // min = min of all constants + // + // If x < 3: + // (1) a[i+x]: Leave unchanged + // (2) a[i+3]: Replace with a[i+max] = a[i+6]: i+x < i+3 <= i+6 -> (2) is covered + // (3) a[i+4]: Replace with a[i+min] = a[i+1]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered + // Remove all other a[i+c] checks + // + // If x >= 3: + // (1) a[i+x]: Leave unchanged + // (2) a[i+3]: Replace with a[i+min] = a[i+1]: i+1 < i+3 <= i+x -> (2) is covered + // (3) a[i+4]: Replace with a[i+max] = a[i+6]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered + // Remove all other a[i+c] checks + // + // We only need the top 2 range checks if x is the min or max of all constants. + // + // This, however, only works if the interval [i+min,i+max] is not larger than max_int (i.e. abs(max - min) < max_int): + // The theoretical max size of an array is max_int with: + // - Valid index space: [0,max_int-1] + // - Invalid index space: [max_int,-1] // max_int, min_int, min_int - 1 ..., -1 + // + // The size of the consecutive valid index space is smaller than the size of the consecutive invalid index space. + // If we choose min and max in such a way that: + // - abs(max - min) < max_int + // - i+max and i+min are inside the valid index space + // then all indices [i+min,i+max] must be in the valid index space. Otherwise, the invalid index space must be + // smaller than the valid index space which is never the case for any array size. + // + // Choosing a smaller array size only makes the valid index space smaller and the invalid index space larger and + // the argument above still holds. + // + // Note that the same optimization with the same maximal accepted interval size can also be found in C1. + const jlong maximum_number_of_min_max_interval_indices = (jlong)max_jint; // The top 3 range checks seen const int NRC = 3; @@ -1906,13 +1946,18 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { found_immediate_dominator = true; break; } - // Gather expanded bounds - off_lo = MIN2(off_lo,offset2); - off_hi = MAX2(off_hi,offset2); - // Record top NRC range checks - prev_checks[nb_checks%NRC].ctl = prev_dom; - prev_checks[nb_checks%NRC].off = offset2; - nb_checks++; + + // "x - y" -> must add one to the difference for number of elements in [x,y] + const jlong diff = (jlong)MIN2(offset2, off_lo) - (jlong)MAX2(offset2, off_hi); + if (ABS(diff) < maximum_number_of_min_max_interval_indices) { + // Gather expanded bounds + off_lo = MIN2(off_lo, offset2); + off_hi = MAX2(off_hi, offset2); + // Record top NRC range checks + prev_checks[nb_checks % NRC].ctl = prev_dom; + prev_checks[nb_checks % NRC].off = offset2; + nb_checks++; + } } } prev_dom = dom; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6e104f09b9d..c2b4eaab1bc 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -492,7 +492,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { "notifyJvmtiMount", false, false); case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()), "notifyJvmtiUnmount", false, false); - case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide(); + case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide(); + case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync(); #endif #ifdef JFR_HAVE_INTRINSICS @@ -2950,6 +2951,29 @@ bool LibraryCallKit::inline_native_notify_jvmti_hide() { return true; } +// Always update the is_disable_suspend bit. +bool LibraryCallKit::inline_native_notify_jvmti_sync() { + if (!DoJVMTIVirtualThreadTransitions) { + return true; + } + IdealKit ideal(this); + + { + // unconditionally update the is_disable_suspend bit in current JavaThread + Node* thread = ideal.thread(); + Node* arg = _gvn.transform(argument(1)); // argument for notification + Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_disable_suspend_offset())); + const TypePtr *addr_type = _gvn.type(addr)->isa_ptr(); + + sync_kit(ideal); + access_store_at(nullptr, addr, addr_type, arg, _gvn.type(arg), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + ideal.sync_kit(this); + } + final_sync(ideal); + + return true; +} + #endif // INCLUDE_JVMTI #ifdef JFR_HAVE_INTRINSICS diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 55d1dc78f1f..47f9d7d4713 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -245,6 +245,7 @@ class LibraryCallKit : public GraphKit { #if INCLUDE_JVMTI bool inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end); bool inline_native_notify_jvmti_hide(); + bool inline_native_notify_jvmti_sync(); #endif #ifdef JFR_HAVE_INTRINSICS diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index d569bfcfab5..ca98f0ffc8c 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -849,9 +849,10 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scal // Check if (scale * max_idx_expr) may overflow const TypeInt* scale_type = TypeInt::make(scale); MulINode* mul = new MulINode(max_idx_expr, con_scale); - idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type); - if (overflow || TypeInt::INT->higher_equal(idx_type)) { + + if (overflow || MulINode::does_overflow(idx_type, scale_type)) { // May overflow + idx_type = TypeInt::INT; mul->destruct(&_igvn); if (!overflow) { max_idx_expr = new ConvI2LNode(max_idx_expr); @@ -864,6 +865,7 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scal } else { // No overflow possible max_idx_expr = mul; + idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type); } register_new_node(max_idx_expr, ctrl); } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index e9655b329e1..ac822453356 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -491,19 +491,19 @@ PhiNode* PhaseIdealLoop::loop_iv_phi(Node* xphi, Node* phi_incr, Node* x, IdealL return phi; } -static int check_stride_overflow(jlong stride_con, const TypeInteger* limit_t, BasicType bt) { - if (stride_con > 0) { - if (limit_t->lo_as_long() > (max_signed_integer(bt) - stride_con)) { +static int check_stride_overflow(jlong final_correction, const TypeInteger* limit_t, BasicType bt) { + if (final_correction > 0) { + if (limit_t->lo_as_long() > (max_signed_integer(bt) - final_correction)) { return -1; } - if (limit_t->hi_as_long() > (max_signed_integer(bt) - stride_con)) { + if (limit_t->hi_as_long() > (max_signed_integer(bt) - final_correction)) { return 1; } } else { - if (limit_t->hi_as_long() < (min_signed_integer(bt) - stride_con)) { + if (limit_t->hi_as_long() < (min_signed_integer(bt) - final_correction)) { return -1; } - if (limit_t->lo_as_long() < (min_signed_integer(bt) - stride_con)) { + if (limit_t->lo_as_long() < (min_signed_integer(bt) - final_correction)) { return 1; } } @@ -1773,49 +1773,204 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ C->print_method(PHASE_BEFORE_CLOOPS, 3); // =================================================== - // Generate loop limit check to avoid integer overflow - // in cases like next (cyclic loops): + // We can only convert this loop to a counted loop if we can guarantee that the iv phi will never overflow at runtime. + // This is an implicit assumption taken by some loop optimizations. We therefore must ensure this property at all cost. + // At this point, we've already excluded some trivial cases where an overflow could have been proven statically. + // But even though we cannot prove that an overflow will *not* happen, we still want to speculatively convert this loop + // to a counted loop. This can be achieved by adding additional iv phi overflow checks before the loop. If they fail, + // we trap and resume execution before the loop without having executed any iteration of the loop, yet. + // + // These additional iv phi overflow checks can be inserted as Loop Limit Check Predicates above the Loop Limit Check + // Parse Predicate which captures a JVM state just before the entry of the loop. If there is no such Parse Predicate, + // we cannot generate a Loop Limit Check Predicate and thus cannot speculatively convert the loop to a counted loop. + // + // In the following, we only focus on int loops with stride > 0 to keep things simple. The argumentation and proof + // for stride < 0 is analogously. For long loops, we would replace max_int with max_long. + // + // + // The loop to be converted does not always need to have the often used shape: + // + // i = init + // i = init loop: + // do { ... + // // ... equivalent i+=stride + // i+=stride <==> if (i < limit) + // } while (i < limit); goto loop + // exit: + // ... + // + // where the loop exit check uses the post-incremented iv phi and a '<'-operator. + // + // We could also have '<='-operator (or '>='-operator for negative strides) or use the pre-incremented iv phi value + // in the loop exit check: + // + // i = init + // loop: + // ... + // if (i <= limit) + // i+=stride + // goto loop + // exit: + // ... + // + // Let's define the following terms: + // - iv_pre_i: The pre-incremented iv phi before the i-th iteration. + // - iv_post_i: The post-incremented iv phi after the i-th iteration. + // + // The iv_pre_i and iv_post_i have the following relation: + // iv_pre_i + stride = iv_post_i + // + // When converting a loop to a counted loop, we want to have a canonicalized loop exit check of the form: + // iv_post_i < adjusted_limit + // + // If that is not the case, we need to canonicalize the loop exit check by using different values for adjusted_limit: + // (LE1) iv_post_i < limit: Already canonicalized. We can directly use limit as adjusted_limit. + // -> adjusted_limit = limit. + // (LE2) iv_post_i <= limit: + // iv_post_i < limit + 1 + // -> adjusted limit = limit + 1 + // (LE3) iv_pre_i < limit: + // iv_pre_i + stride < limit + stride + // iv_post_i < limit + stride + // -> adjusted_limit = limit + stride + // (LE4) iv_pre_i <= limit: + // iv_pre_i < limit + 1 + // iv_pre_i + stride < limit + stride + 1 + // iv_post_i < limit + stride + 1 + // -> adjusted_limit = limit + stride + 1 + // + // Note that: + // (AL) limit <= adjusted_limit. + // + // The following loop invariant has to hold for counted loops with n iterations (i.e. loop exit check true after n-th + // loop iteration) and a canonicalized loop exit check to guarantee that no iv_post_i over- or underflows: + // (INV) For i = 1..n, min_int <= iv_post_i <= max_int + // + // To prove (INV), we require the following two conditions/assumptions: + // (i): adjusted_limit - 1 + stride <= max_int + // (ii): init < limit + // + // If we can prove (INV), we know that there can be no over- or underflow of any iv phi value. We prove (INV) by + // induction by assuming (i) and (ii). + // + // Proof by Induction + // ------------------ + // > Base case (i = 1): We show that (INV) holds after the first iteration: + // min_int <= iv_post_1 = init + stride <= max_int + // Proof: + // First, we note that (ii) implies + // (iii) init <= limit - 1 + // max_int >= adjusted_limit - 1 + stride [using (i)] + // >= limit - 1 + stride [using (AL)] + // >= init + stride [using (iii)] + // >= min_int [using stride > 0, no underflow] + // Thus, no overflow happens after the first iteration and (INV) holds for i = 1. + // + // Note that to prove the base case we need (i) and (ii). + // + // > Induction Hypothesis (i = j, j > 1): Assume that (INV) holds after the j-th iteration: + // min_int <= iv_post_j <= max_int + // > Step case (i = j + 1): We show that (INV) also holds after the j+1-th iteration: + // min_int <= iv_post_{j+1} = iv_post_j + stride <= max_int + // Proof: + // If iv_post_j >= adjusted_limit: + // We exit the loop after the j-th iteration, and we don't execute the j+1-th iteration anymore. Thus, there is + // also no iv_{j+1}. Since (INV) holds for iv_j, there is nothing left to prove. + // If iv_post_j < adjusted_limit: + // First, we note that: + // (iv) iv_post_j <= adjusted_limit - 1 + // max_int >= adjusted_limit - 1 + stride [using (i)] + // >= iv_post_j + stride [using (iv)] + // >= min_int [using stride > 0, no underflow] // - // for (i=0; i <= max_jint; i++) {} - // for (i=0; i < max_jint; i+=2) {} + // Note that to prove the step case we only need (i). // + // Thus, by assuming (i) and (ii), we proved (INV). // - // Limit check predicate depends on the loop test: // - // for(;i != limit; i++) --> limit <= (max_jint) - // for(;i < limit; i+=stride) --> limit <= (max_jint - stride + 1) - // for(;i <= limit; i+=stride) --> limit <= (max_jint - stride ) + // It is therefore enough to add the following two Loop Limit Check Predicates to check assumptions (i) and (ii): // + // (1) Loop Limit Check Predicate for (i): + // Using (i): adjusted_limit - 1 + stride <= max_int + // + // This condition is now restated to use limit instead of adjusted_limit: + // + // To prevent an overflow of adjusted_limit -1 + stride itself, we rewrite this check to + // max_int - stride + 1 >= adjusted_limit + // We can merge the two constants into + // canonicalized_correction = stride - 1 + // which gives us + // max_int - canonicalized_correction >= adjusted_limit + // + // To directly use limit instead of adjusted_limit in the predicate condition, we split adjusted_limit into: + // adjusted_limit = limit + limit_correction + // Since stride > 0 and limit_correction <= stride + 1, we can restate this with no over- or underflow into: + // max_int - canonicalized_correction - limit_correction >= limit + // Since canonicalized_correction and limit_correction are both constants, we can replace them with a new constant: + // final_correction = canonicalized_correction + limit_correction + // which gives us: + // + // Final predicate condition: + // max_int - final_correction >= limit + // + // (2) Loop Limit Check Predicate for (ii): + // Using (ii): init < limit + // + // This Loop Limit Check Predicate is not required if we can prove at compile time that either: + // (2.1) type(init) < type(limit) + // In this case, we know: + // all possible values of init < all possible values of limit + // and we can skip the predicate. + // + // (2.2) init < limit is already checked before (i.e. found as a dominating check) + // In this case, we do not need to re-check the condition and can skip the predicate. + // This is often found for while- and for-loops which have the following shape: + // + // if (init < limit) { // Dominating test. Do not need the Loop Limit Check Predicate below. + // i = init; + // if (init >= limit) { trap(); } // Here we would insert the Loop Limit Check Predicate + // do { + // i += stride; + // } while (i < limit); + // } + // + // (2.3) init + stride <= max_int + // In this case, there is no overflow of the iv phi after the first loop iteration. + // In the proof of the base case above we showed that init + stride <= max_int by using assumption (ii): + // init < limit + // In the proof of the step case above, we did not need (ii) anymore. Therefore, if we already know at + // compile time that init + stride <= max_int then we have trivially proven the base case and that + // there is no overflow of the iv phi after the first iteration. In this case, we don't need to check (ii) + // again and can skip the predicate. - // Check if limit is excluded to do more precise int overflow check. - bool incl_limit = (bt == BoolTest::le || bt == BoolTest::ge); - jlong stride_m = stride_con - (incl_limit ? 0 : (stride_con > 0 ? 1 : -1)); - // If compare points directly to the phi we need to adjust - // the compare so that it points to the incr. Limit have - // to be adjusted to keep trip count the same and the - // adjusted limit should be checked for int overflow. - Node* adjusted_limit = limit; - if (phi_incr != nullptr) { - stride_m += stride_con; - } + // Accounting for (LE3) and (LE4) where we use pre-incremented phis in the loop exit check. + const jlong limit_correction_for_pre_iv_exit_check = (phi_incr != nullptr) ? stride_con : 0; - Node *init_control = x->in(LoopNode::EntryControl); + // Accounting for (LE2) and (LE4) where we use <= or >= in the loop exit check. + const bool includes_limit = (bt == BoolTest::le || bt == BoolTest::ge); + const jlong limit_correction_for_le_ge_exit_check = (includes_limit ? (stride_con > 0 ? 1 : -1) : 0); + + const jlong limit_correction = limit_correction_for_pre_iv_exit_check + limit_correction_for_le_ge_exit_check; + const jlong canonicalized_correction = stride_con + (stride_con > 0 ? -1 : 1); + const jlong final_correction = canonicalized_correction + limit_correction; + + int sov = check_stride_overflow(final_correction, limit_t, iv_bt); + Node* init_control = x->in(LoopNode::EntryControl); - int sov = check_stride_overflow(stride_m, limit_t, iv_bt); // If sov==0, limit's type always satisfies the condition, for // example, when it is an array length. if (sov != 0) { if (sov < 0) { return false; // Bailout: integer overflow is certain. } + // (1) Loop Limit Check Predicate is required because we could not statically prove that + // limit + final_correction = adjusted_limit - 1 + stride <= max_int assert(!x->as_Loop()->is_loop_nest_inner_loop(), "loop was transformed"); - // Generate loop's limit check. - // Loop limit check predicate should be near the loop. const Predicates predicates(init_control); const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); if (!loop_limit_check_predicate_block->has_parse_predicate()) { - // The limit check predicate is not generated if this method trapped here before. + // The Loop Limit Check Parse Predicate is not generated if this method trapped here before. #ifdef ASSERT if (TraceLoopLimitCheck) { tty->print("Missing Loop Limit Check Parse Predicate:"); @@ -1835,67 +1990,81 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ Node* bol; if (stride_con > 0) { - cmp_limit = CmpNode::make(limit, _igvn.integercon(max_signed_integer(iv_bt) - stride_m, iv_bt), iv_bt); + cmp_limit = CmpNode::make(limit, _igvn.integercon(max_signed_integer(iv_bt) - final_correction, iv_bt), iv_bt); bol = new BoolNode(cmp_limit, BoolTest::le); } else { - cmp_limit = CmpNode::make(limit, _igvn.integercon(min_signed_integer(iv_bt) - stride_m, iv_bt), iv_bt); + cmp_limit = CmpNode::make(limit, _igvn.integercon(min_signed_integer(iv_bt) - final_correction, iv_bt), iv_bt); bol = new BoolNode(cmp_limit, BoolTest::ge); } insert_loop_limit_check_predicate(init_control->as_IfTrue(), cmp_limit, bol); } - // Now we need to canonicalize loop condition. - if (bt == BoolTest::ne) { - assert(stride_con == 1 || stride_con == -1, "simple increment only"); - if (stride_con > 0 && init_t->hi_as_long() < limit_t->lo_as_long()) { - // 'ne' can be replaced with 'lt' only when init < limit. - bt = BoolTest::lt; - } else if (stride_con < 0 && init_t->lo_as_long() > limit_t->hi_as_long()) { - // 'ne' can be replaced with 'gt' only when init > limit. - bt = BoolTest::gt; - } else { - const Predicates predicates(init_control); - const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); - if (!loop_limit_check_predicate_block->has_parse_predicate()) { - // The limit check predicate is not generated if this method trapped here before. + // (2.3) + const bool init_plus_stride_could_overflow = + (stride_con > 0 && init_t->hi_as_long() > max_signed_integer(iv_bt) - stride_con) || + (stride_con < 0 && init_t->lo_as_long() < min_signed_integer(iv_bt) - stride_con); + // (2.1) + const bool init_gte_limit = (stride_con > 0 && init_t->hi_as_long() >= limit_t->lo_as_long()) || + (stride_con < 0 && init_t->lo_as_long() <= limit_t->hi_as_long()); + + if (init_gte_limit && // (2.1) + ((bt == BoolTest::ne || init_plus_stride_could_overflow) && // (2.3) + !has_dominating_loop_limit_check(init_trip, limit, stride_con, iv_bt, init_control))) { // (2.2) + // (2) Iteration Loop Limit Check Predicate is required because neither (2.1), (2.2), nor (2.3) holds. + // We use the following condition: + // - stride > 0: init < limit + // - stride < 0: init > limit + // + // This predicate is always required if we have a non-equal-operator in the loop exit check (where stride = 1 is + // a requirement). We transform the loop exit check by using a less-than-operator. By doing so, we must always + // check that init < limit. Otherwise, we could have a different number of iterations at runtime. + + const Predicates predicates(init_control); + const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); + if (!loop_limit_check_predicate_block->has_parse_predicate()) { + // The Loop Limit Check Parse Predicate is not generated if this method trapped here before. #ifdef ASSERT - if (TraceLoopLimitCheck) { - tty->print("Missing Loop Limit Check Parse Predicate:"); - loop->dump_head(); - x->dump(1); - } -#endif - return false; + if (TraceLoopLimitCheck) { + tty->print("Missing Loop Limit Check Parse Predicate:"); + loop->dump_head(); + x->dump(1); } +#endif + return false; + } - ParsePredicateNode* loop_limit_check_parse_predicate = loop_limit_check_predicate_block->parse_predicate(); - Node* parse_predicate_entry = loop_limit_check_parse_predicate->in(0); - if (!is_dominator(get_ctrl(limit), parse_predicate_entry) || - !is_dominator(get_ctrl(init_trip), parse_predicate_entry)) { - return false; - } + ParsePredicateNode* loop_limit_check_parse_predicate = loop_limit_check_predicate_block->parse_predicate(); + Node* parse_predicate_entry = loop_limit_check_parse_predicate->in(0); + if (!is_dominator(get_ctrl(limit), parse_predicate_entry) || + !is_dominator(get_ctrl(init_trip), parse_predicate_entry)) { + return false; + } - Node* cmp_limit; - Node* bol; + Node* cmp_limit; + Node* bol; - if (stride_con > 0) { - cmp_limit = CmpNode::make(init_trip, limit, iv_bt); - bol = new BoolNode(cmp_limit, BoolTest::lt); - } else { - cmp_limit = CmpNode::make(init_trip, limit, iv_bt); - bol = new BoolNode(cmp_limit, BoolTest::gt); - } + if (stride_con > 0) { + cmp_limit = CmpNode::make(init_trip, limit, iv_bt); + bol = new BoolNode(cmp_limit, BoolTest::lt); + } else { + cmp_limit = CmpNode::make(init_trip, limit, iv_bt); + bol = new BoolNode(cmp_limit, BoolTest::gt); + } - insert_loop_limit_check_predicate(init_control->as_IfTrue(), cmp_limit, bol); + insert_loop_limit_check_predicate(init_control->as_IfTrue(), cmp_limit, bol); + } - if (stride_con > 0) { - // 'ne' can be replaced with 'lt' only when init < limit. - bt = BoolTest::lt; - } else if (stride_con < 0) { - // 'ne' can be replaced with 'gt' only when init > limit. - bt = BoolTest::gt; - } + if (bt == BoolTest::ne) { + // Now we need to canonicalize the loop condition if it is 'ne'. + assert(stride_con == 1 || stride_con == -1, "simple increment only - checked before"); + if (stride_con > 0) { + // 'ne' can be replaced with 'lt' only when init < limit. This is ensured by the inserted predicate above. + bt = BoolTest::lt; + } else { + assert(stride_con < 0, "must be"); + // 'ne' can be replaced with 'gt' only when init > limit. This is ensured by the inserted predicate above. + bt = BoolTest::gt; } } @@ -1940,6 +2109,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ } #endif + Node* adjusted_limit = limit; if (phi_incr != nullptr) { // If compare points directly to the phi we need to adjust // the compare so that it points to the incr. Limit have @@ -1953,7 +2123,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ adjusted_limit = gvn->transform(AddNode::make(limit, stride, iv_bt)); } - if (incl_limit) { + if (includes_limit) { // The limit check guaranties that 'limit <= (max_jint - stride)' so // we can convert 'i <= limit' to 'i < limit+1' since stride != 0. // @@ -2134,6 +2304,37 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ return true; } +// Check if there is a dominating loop limit check of the form 'init < limit' starting at the loop entry. +// If there is one, then we do not need to create an additional Loop Limit Check Predicate. +bool PhaseIdealLoop::has_dominating_loop_limit_check(Node* init_trip, Node* limit, const jlong stride_con, + const BasicType iv_bt, Node* loop_entry) { + // Eagerly call transform() on the Cmp and Bool node to common them up if possible. This is required in order to + // successfully find a dominated test with the If node below. + Node* cmp_limit; + Node* bol; + if (stride_con > 0) { + cmp_limit = _igvn.transform(CmpNode::make(init_trip, limit, iv_bt)); + bol = _igvn.transform(new BoolNode(cmp_limit, BoolTest::lt)); + } else { + cmp_limit = _igvn.transform(CmpNode::make(init_trip, limit, iv_bt)); + bol = _igvn.transform(new BoolNode(cmp_limit, BoolTest::gt)); + } + + // Check if there is already a dominating init < limit check. If so, we do not need a Loop Limit Check Predicate. + IfNode* iff = new IfNode(loop_entry, bol, PROB_MIN, COUNT_UNKNOWN); + // Also add fake IfProj nodes in order to call transform() on the newly created IfNode. + IfFalseNode* if_false = new IfFalseNode(iff); + IfTrueNode* if_true = new IfTrueNode(iff); + Node* dominated_iff = _igvn.transform(iff); + // ConI node? Found dominating test (IfNode::dominated_by() returns a ConI node). + const bool found_dominating_test = dominated_iff != nullptr && dominated_iff->is_ConI(); + + // Kill the If with its projections again in the next IGVN round by cutting it off from the graph. + _igvn.replace_input_of(iff, 0, C->top()); + _igvn.replace_input_of(iff, 1, C->top()); + return found_dominating_test; +} + //----------------------exact_limit------------------------------------------- Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) { assert(loop->_head->is_CountedLoop(), ""); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 4a34d7e49ba..a074e9231ef 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1346,6 +1346,8 @@ class PhaseIdealLoop : public PhaseTransform { void rewire_cloned_nodes_to_ctrl(const ProjNode* old_ctrl, Node* new_ctrl, const Node_List& nodes_with_same_ctrl, const Dict& old_new_mapping); void rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clone, const Dict& old_new_mapping, const Node* next); + bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, jlong stride_con, BasicType iv_bt, + Node* loop_entry); public: void register_control(Node* n, IdealLoopTree *loop, Node* pred, bool update_body = true); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index ea1bdc933d0..ceda232a969 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -287,7 +287,11 @@ bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) co return false; } - assert(n->in(0) == nullptr, "divisions with zero check should already have bailed out earlier in split-if"); + if (n->in(0) != nullptr) { + // Cannot split through phi if Div or Mod node has a control dependency to a zero check. + return true; + } + Node* divisor = n->in(2); return is_divisor_counted_loop_phi(divisor, region) && loop_phi_backedge_type_contains_zero(divisor, zero); diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 3b493b5efa2..a59ec86a2b6 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -281,45 +281,86 @@ Node *MulINode::Ideal(PhaseGVN *phase, bool can_reshape) { return res; // Return final result } -// Classes to perform mul_ring() for MulI/MulLNode. +// This template class performs type multiplication for MulI/MulLNode. NativeType is either jint or jlong. +// In this class, the inputs of the MulNodes are named left and right with types [left_lo,left_hi] and [right_lo,right_hi]. // -// This class checks if all cross products of the left and right input of a multiplication have the same "overflow value". -// Without overflow/underflow: -// Product is positive? High signed multiplication result: 0 -// Product is negative? High signed multiplication result: -1 +// In general, the multiplication of two x-bit values could produce a result that consumes up to 2x bits if there is +// enough space to hold them all. We can therefore distinguish the following two cases for the product: +// - no overflow (i.e. product fits into x bits) +// - overflow (i.e. product does not fit into x bits) // -// We normalize these values (see normalize_overflow_value()) such that we get the same "overflow value" by adding 1 if -// the product is negative. This allows us to compare all the cross product "overflow values". If one is different, -// compared to the others, then we know that this multiplication has a different number of over- or underflows compared -// to the others. In this case, we need to use bottom type and cannot guarantee a better type. Otherwise, we can take -// the min und max of all computed cross products as type of this Mul node. -template -class IntegerMulRing { - using NativeType = std::conditional_t::value, jint, jlong>; +// When multiplying the two x-bit inputs 'left' and 'right' with their x-bit types [left_lo,left_hi] and [right_lo,right_hi] +// we need to find the minimum and maximum of all possible products to define a new type. To do that, we compute the +// cross product of [left_lo,left_hi] and [right_lo,right_hi] in 2x-bit space where no over- or underflow can happen. +// The cross product consists of the following four multiplications with 2x-bit results: +// (1) left_lo * right_lo +// (2) left_lo * right_hi +// (3) left_hi * right_lo +// (4) left_hi * right_hi +// +// Let's define the following two functions: +// - Lx(i): Returns the lower x bits of the 2x-bit number i. +// - Ux(i): Returns the upper x bits of the 2x-bit number i. +// +// Let's first assume all products are positive where only overflows are possible but no underflows. If there is no +// overflow for a product p, then the upper x bits of the 2x-bit result p are all zero: +// Ux(p) = 0 +// Lx(p) = p +// +// If none of the multiplications (1)-(4) overflow, we can truncate the upper x bits and use the following result type +// with x bits: +// [result_lo,result_hi] = [MIN(Lx(1),Lx(2),Lx(3),Lx(4)),MAX(Lx(1),Lx(2),Lx(3),Lx(4))] +// +// If any of these multiplications overflows, we could pessimistically take the bottom type for the x bit result +// (i.e. all values in the x-bit space could be possible): +// [result_lo,result_hi] = [NativeType_min,NativeType_max] +// +// However, in case of any overflow, we can do better by analyzing the upper x bits of all multiplications (1)-(4) with +// 2x-bit results. The upper x bits tell us something about how many times a multiplication has overflown the lower +// x bits. If the upper x bits of (1)-(4) are all equal, then we know that all of these multiplications overflowed +// the lower x bits the same number of times: +// Ux((1)) = Ux((2)) = Ux((3)) = Ux((4)) +// +// If all upper x bits are equal, we can conclude: +// Lx(MIN((1),(2),(3),(4))) = MIN(Lx(1),Lx(2),Lx(3),Lx(4))) +// Lx(MAX((1),(2),(3),(4))) = MAX(Lx(1),Lx(2),Lx(3),Lx(4))) +// +// Therefore, we can use the same precise x-bit result type as for the no-overflow case: +// [result_lo,result_hi] = [(MIN(Lx(1),Lx(2),Lx(3),Lx(4))),MAX(Lx(1),Lx(2),Lx(3),Lx(4)))] +// +// +// Now let's assume that (1)-(4) are signed multiplications where over- and underflow could occur: +// Negative numbers are all sign extend with ones. Therefore, if a negative product does not underflow, then the +// upper x bits of the 2x-bit result are all set to ones which is minus one in two's complement. If there is an underflow, +// the upper x bits are decremented by the number of times an underflow occurred. The smallest possible negative product +// is NativeType_min*NativeType_max, where the upper x bits are set to NativeType_min / 2 (b11...0). It is therefore +// impossible to underflow the upper x bits. Thus, when having all ones (i.e. minus one) in the upper x bits, we know +// that there is no underflow. +// +// To be able to compare the number of over-/underflows of positive and negative products, respectively, we normalize +// the upper x bits of negative 2x-bit products by adding one. This way a product has no over- or underflow if the +// normalized upper x bits are zero. Now we can use the same improved type as for strictly positive products because we +// can compare the upper x bits in a unified way with N() being the normalization function: +// N(Ux((1))) = N(Ux((2))) = N(Ux((3)) = N(Ux((4))) +template +class IntegerTypeMultiplication { NativeType _lo_left; NativeType _lo_right; NativeType _hi_left; NativeType _hi_right; - NativeType _lo_lo_product; - NativeType _lo_hi_product; - NativeType _hi_lo_product; - NativeType _hi_hi_product; short _widen_left; short _widen_right; static const Type* overflow_type(); - static NativeType multiply_high_signed_overflow_value(NativeType x, NativeType y); + static NativeType multiply_high(NativeType x, NativeType y); + const Type* create_type(NativeType lo, NativeType hi) const; - // Pre-compute cross products which are used at several places - void compute_cross_products() { - _lo_lo_product = java_multiply(_lo_left, _lo_right); - _lo_hi_product = java_multiply(_lo_left, _hi_right); - _hi_lo_product = java_multiply(_hi_left, _lo_right); - _hi_hi_product = java_multiply(_hi_left, _hi_right); + static NativeType multiply_high_signed_overflow_value(NativeType x, NativeType y) { + return normalize_overflow_value(x, y, multiply_high(x, y)); } - bool cross_products_not_same_overflow() const { + bool cross_product_not_same_overflow_value() const { const NativeType lo_lo_high_product = multiply_high_signed_overflow_value(_lo_left, _lo_right); const NativeType lo_hi_high_product = multiply_high_signed_overflow_value(_lo_left, _hi_right); const NativeType hi_lo_high_product = multiply_high_signed_overflow_value(_hi_left, _lo_right); @@ -329,66 +370,95 @@ class IntegerMulRing { hi_lo_high_product != hi_hi_high_product; } + bool does_product_overflow(NativeType x, NativeType y) const { + return multiply_high_signed_overflow_value(x, y) != 0; + } + static NativeType normalize_overflow_value(const NativeType x, const NativeType y, NativeType result) { return java_multiply(x, y) < 0 ? result + 1 : result; } public: - IntegerMulRing(const IntegerType* left, const IntegerType* right) : _lo_left(left->_lo), _lo_right(right->_lo), - _hi_left(left->_hi), _hi_right(right->_hi), _widen_left(left->_widen), _widen_right(right->_widen) { - compute_cross_products(); - } + template + IntegerTypeMultiplication(const IntegerType* left, const IntegerType* right) + : _lo_left(left->_lo), _lo_right(right->_lo), + _hi_left(left->_hi), _hi_right(right->_hi), + _widen_left(left->_widen), _widen_right(right->_widen) {} // Compute the product type by multiplying the two input type ranges. We take the minimum and maximum of all possible // values (requires 4 multiplications of all possible combinations of the two range boundary values). If any of these // multiplications overflows/underflows, we need to make sure that they all have the same number of overflows/underflows // If that is not the case, we return the bottom type to cover all values due to the inconsistent overflows/underflows). const Type* compute() const { - if (cross_products_not_same_overflow()) { + if (cross_product_not_same_overflow_value()) { return overflow_type(); } - const NativeType min = MIN4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product); - const NativeType max = MAX4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product); - return IntegerType::make(min, max, MAX2(_widen_left, _widen_right)); + + NativeType lo_lo_product = java_multiply(_lo_left, _lo_right); + NativeType lo_hi_product = java_multiply(_lo_left, _hi_right); + NativeType hi_lo_product = java_multiply(_hi_left, _lo_right); + NativeType hi_hi_product = java_multiply(_hi_left, _hi_right); + const NativeType min = MIN4(lo_lo_product, lo_hi_product, hi_lo_product, hi_hi_product); + const NativeType max = MAX4(lo_lo_product, lo_hi_product, hi_lo_product, hi_hi_product); + return create_type(min, max); } -}; + bool does_overflow() const { + return does_product_overflow(_lo_left, _lo_right) || + does_product_overflow(_lo_left, _hi_right) || + does_product_overflow(_hi_left, _lo_right) || + does_product_overflow(_hi_left, _hi_right); + } +}; template <> -const Type* IntegerMulRing::overflow_type() { +const Type* IntegerTypeMultiplication::overflow_type() { return TypeInt::INT; } template <> -jint IntegerMulRing::multiply_high_signed_overflow_value(const jint x, const jint y) { +jint IntegerTypeMultiplication::multiply_high(const jint x, const jint y) { const jlong x_64 = x; const jlong y_64 = y; const jlong product = x_64 * y_64; - const jint result = (jint)((uint64_t)product >> 32u); - return normalize_overflow_value(x, y, result); + return (jint)((uint64_t)product >> 32u); +} + +template <> +const Type* IntegerTypeMultiplication::create_type(jint lo, jint hi) const { + return TypeInt::make(lo, hi, MAX2(_widen_left, _widen_right)); } template <> -const Type* IntegerMulRing::overflow_type() { +const Type* IntegerTypeMultiplication::overflow_type() { return TypeLong::LONG; } template <> -jlong IntegerMulRing::multiply_high_signed_overflow_value(const jlong x, const jlong y) { - const jlong result = multiply_high_signed(x, y); - return normalize_overflow_value(x, y, result); +jlong IntegerTypeMultiplication::multiply_high(const jlong x, const jlong y) { + return multiply_high_signed(x, y); +} + +template <> +const Type* IntegerTypeMultiplication::create_type(jlong lo, jlong hi) const { + return TypeLong::make(lo, hi, MAX2(_widen_left, _widen_right)); } // Compute the product type of two integer ranges into this node. const Type* MulINode::mul_ring(const Type* type_left, const Type* type_right) const { - const IntegerMulRing integer_mul_ring(type_left->is_int(), type_right->is_int()); - return integer_mul_ring.compute(); + const IntegerTypeMultiplication integer_multiplication(type_left->is_int(), type_right->is_int()); + return integer_multiplication.compute(); +} + +bool MulINode::does_overflow(const TypeInt* type_left, const TypeInt* type_right) { + const IntegerTypeMultiplication integer_multiplication(type_left, type_right); + return integer_multiplication.does_overflow(); } // Compute the product type of two long ranges into this node. const Type* MulLNode::mul_ring(const Type* type_left, const Type* type_right) const { - const IntegerMulRing integer_mul_ring(type_left->is_long(), type_right->is_long()); - return integer_mul_ring.compute(); + const IntegerTypeMultiplication integer_multiplication(type_left->is_long(), type_right->is_long()); + return integer_multiplication.compute(); } //============================================================================= diff --git a/src/hotspot/share/opto/mulnode.hpp b/src/hotspot/share/opto/mulnode.hpp index d04648ee61a..10ef442299d 100644 --- a/src/hotspot/share/opto/mulnode.hpp +++ b/src/hotspot/share/opto/mulnode.hpp @@ -95,6 +95,7 @@ class MulINode : public MulNode { virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *mul_ring( const Type *, const Type * ) const; + static bool does_overflow(const TypeInt* type_left, const TypeInt* type_right); const Type *mul_id() const { return TypeInt::ONE; } const Type *add_id() const { return TypeInt::ZERO; } int add_opcode() const { return Op_AddI; } diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 64d98f27ff6..9481b91ce39 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.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 @@ -775,7 +775,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, SafePointScalarMergeNode* smerge = local->as_SafePointScalarMerge(); ObjectMergeValue* mv = (ObjectMergeValue*) sv_for_node_id(objs, smerge->_idx); - if (mv == NULL) { + if (mv == nullptr) { GrowableArray deps; int merge_pointer_idx = smerge->merge_pointer_idx(sfpt->jvms()); @@ -783,7 +783,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, assert(deps.length() == 1, "missing value"); int selector_idx = smerge->selector_idx(sfpt->jvms()); - (void)FillLocArray(1, NULL, sfpt->in(selector_idx), &deps, NULL); + (void)FillLocArray(1, nullptr, sfpt->in(selector_idx), &deps, nullptr); assert(deps.length() == 2, "missing value"); mv = new ObjectMergeValue(smerge->_idx, deps.at(0), deps.at(1)); @@ -1085,6 +1085,30 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { } scval = sv; } + } else if (obj_node->is_SafePointScalarMerge()) { + SafePointScalarMergeNode* smerge = obj_node->as_SafePointScalarMerge(); + ObjectMergeValue* mv = (ObjectMergeValue*) sv_for_node_id(objs, smerge->_idx); + + if (mv == nullptr) { + GrowableArray deps; + + int merge_pointer_idx = smerge->merge_pointer_idx(youngest_jvms); + FillLocArray(0, sfn, sfn->in(merge_pointer_idx), &deps, objs); + assert(deps.length() == 1, "missing value"); + + int selector_idx = smerge->selector_idx(youngest_jvms); + FillLocArray(1, nullptr, sfn->in(selector_idx), &deps, nullptr); + assert(deps.length() == 2, "missing value"); + + mv = new ObjectMergeValue(smerge->_idx, deps.at(0), deps.at(1)); + set_sv_for_object_node(objs, mv); + + for (uint i = 1; i < smerge->req(); i++) { + Node* obj_node = smerge->in(i); + FillLocArray(mv->possible_objects()->length(), sfn, obj_node, mv->possible_objects(), objs); + } + } + scval = mv; } else if (!obj_node->is_Con()) { OptoReg::Name obj_reg = C->regalloc()->get_reg_first(obj_node); if( obj_node->bottom_type()->base() == Type::NarrowOop ) { diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp index 1011cb54245..393585d453c 100644 --- a/src/hotspot/share/opto/subtypenode.cpp +++ b/src/hotspot/share/opto/subtypenode.cpp @@ -43,18 +43,6 @@ const Type* SubTypeCheckNode::sub(const Type* sub_t, const Type* super_t) const if (!superklass->is_interface() && superklass->is_abstract() && !superklass->as_instance_klass()->has_subklass()) { Compile::current()->dependencies()->assert_leaf_type(superklass); - if (subk->is_same_java_type_as(superk) && !sub_t->maybe_null()) { - // The super_t has no subclasses, and sub_t has the same type and is not null, - // hence the check should always evaluate to EQ. However, this is an impossible - // situation since super_t is also abstract, and hence sub_t cannot have the - // same type and be non-null. - // Still, if the non-static method of an abstract class without subclasses is - // force-compiled, the Param0 has the self/this pointer with NotNull. This - // method would now never be called, because of the leaf-type dependency. Hence, - // just for consistency with verification, we return EQ. - return TypeInt::CC_EQ; - } - // subk is either a supertype of superk, or null. In either case, superk is a subtype. return TypeInt::CC_GT; } } diff --git a/src/hotspot/share/prims/foreignGlobals.cpp b/src/hotspot/share/prims/foreignGlobals.cpp index f3653d29886..11b0b8ace7c 100644 --- a/src/hotspot/share/prims/foreignGlobals.cpp +++ b/src/hotspot/share/prims/foreignGlobals.cpp @@ -140,7 +140,7 @@ int ForeignGlobals::compute_out_arg_bytes(const GrowableArray& out_re int ForeignGlobals::java_calling_convention(const BasicType* signature, int num_args, GrowableArray& out_regs) { VMRegPair* vm_regs = NEW_RESOURCE_ARRAY(VMRegPair, num_args); - int slots = SharedRuntime::java_calling_convention(signature, vm_regs, num_args); + int slots = align_up(SharedRuntime::java_calling_convention(signature, vm_regs, num_args), 2); for (int i = 0; i < num_args; i++) { VMRegPair pair = vm_regs[i]; // note, we ignore second here. Signature should consist of register-size values. So there should be diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 33dcfb6c3fe..b6a4443a8c7 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -930,6 +930,11 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive } } + if (selected_method->is_abstract()) { + ResourceMark rm(THREAD); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), selected_method->name()->as_C_string()); + } + methodHandle method(THREAD, selected_method); // Create object to hold arguments for the JavaCall, and associate it with diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index f0a30ee0311..9a8a9a5bec0 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3933,8 +3933,6 @@ JVM_ENTRY(void, JVM_VirtualThreadStart(JNIEnv* env, jobject vthread)) // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, false); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -3950,8 +3948,6 @@ JVM_ENTRY(void, JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread)) // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, true); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -3969,8 +3965,6 @@ JVM_ENTRY(void, JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hi // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -3988,8 +3982,6 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -4003,8 +3995,20 @@ JVM_ENTRY(void, JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboole assert(!thread->is_in_VTMS_transition(), "sanity check"); assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check"); thread->toggle_is_in_tmp_VTMS_transition(); -#else - fatal("Should only be called with JVMTI enabled"); +#endif +JVM_END + +// Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section. +// Needed to avoid deadlocks with JVMTI suspend mechanism. +JVM_ENTRY(void, JVM_VirtualThreadDisableSuspend(JNIEnv* env, jobject vthread, jboolean enter)) +#if INCLUDE_JVMTI + if (!DoJVMTIVirtualThreadTransitions) { + assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); + return; + } + assert(thread->is_disable_suspend() != (bool)enter, + "nested or unbalanced monitor enter/exit is not allowed"); + thread->toggle_is_disable_suspend(); #endif JVM_END diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 9d6296ee316..6a3ee718709 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -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 @@ -2407,6 +2407,7 @@ UpdateForPopTopFrameClosure::doit(Thread *target, bool self) { void SetFramePopClosure::do_thread(Thread *target) { Thread* current = Thread::current(); + ResourceMark rm(current); // vframes are resource allocated JavaThread* java_thread = JavaThread::cast(target); if (java_thread->is_exiting()) { @@ -2433,6 +2434,9 @@ SetFramePopClosure::do_thread(Thread *target) { void SetFramePopClosure::do_vthread(Handle target_h) { + Thread* current = Thread::current(); + ResourceMark rm(current); // vframes are resource allocated + if (!_self && !JvmtiVTSuspender::is_vthread_suspended(target_h())) { _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; return; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index fd8f155af42..250bef15869 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -315,7 +315,6 @@ static bool matches_property_suffix(const char* option, const char* property, si // any of the reserved module properties. // property should be passed without the leading "-D". bool Arguments::is_internal_module_property(const char* property) { - assert((strncmp(property, "-D", 2) != 0), "Unexpected leading -D"); if (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) { const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN; if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) || diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index fe1dfc62ee4..969e14f150e 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -1775,7 +1775,7 @@ class ThawBase : public StackObj { inline void before_thaw_java_frame(const frame& hf, const frame& caller, bool bottom, int num_frame); inline void after_thaw_java_frame(const frame& f, bool bottom); inline void patch(frame& f, const frame& caller, bool bottom); - void clear_bitmap_bits(intptr_t* start, int range); + void clear_bitmap_bits(address start, address end); NOINLINE void recurse_thaw_interpreted_frame(const frame& hf, frame& caller, int num_frames); void recurse_thaw_compiled_frame(const frame& hf, frame& caller, int num_frames, bool stub_caller); @@ -2166,13 +2166,22 @@ inline void ThawBase::patch(frame& f, const frame& caller, bool bottom) { assert(!bottom || (_cont.is_empty() != Continuation::is_cont_barrier_frame(f)), ""); } -void ThawBase::clear_bitmap_bits(intptr_t* start, int range) { +void ThawBase::clear_bitmap_bits(address start, address end) { + assert(is_aligned(start, wordSize), "should be aligned: " PTR_FORMAT, p2i(start)); + assert(is_aligned(end, VMRegImpl::stack_slot_size), "should be aligned: " PTR_FORMAT, p2i(end)); + // we need to clear the bits that correspond to arguments as they reside in the caller frame - // or they will keep objects that are otherwise unreachable alive - log_develop_trace(continuations)("clearing bitmap for " INTPTR_FORMAT " - " INTPTR_FORMAT, p2i(start), p2i(start+range)); + // or they will keep objects that are otherwise unreachable alive. + + // Align `end` if UseCompressedOops is not set to avoid UB when calculating the bit index, since + // `end` could be at an odd number of stack slots from `start`, i.e might not be oop aligned. + // If that's the case the bit range corresponding to the last stack slot should not have bits set + // anyways and we assert that before returning. + address effective_end = UseCompressedOops ? end : align_down(end, wordSize); + log_develop_trace(continuations)("clearing bitmap for " INTPTR_FORMAT " - " INTPTR_FORMAT, p2i(start), p2i(effective_end)); stackChunkOop chunk = _cont.tail(); - chunk->bitmap().clear_range(chunk->bit_index_for(start), - chunk->bit_index_for(start+range)); + chunk->bitmap().clear_range(chunk->bit_index_for(start), chunk->bit_index_for(effective_end)); + assert(chunk->bitmap().count_one_bits(chunk->bit_index_for(effective_end), chunk->bit_index_for(end)) == 0, "bits should not be set"); } NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& caller, int num_frames) { @@ -2225,7 +2234,9 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); } else if (_cont.tail()->has_bitmap() && locals > 0) { assert(hf.is_heap_frame(), "should be"); - clear_bitmap_bits(heap_frame_bottom - locals, locals); + address start = (address)(heap_frame_bottom - locals); + address end = (address)heap_frame_bottom; + clear_bitmap_bits(start, end); } DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);) @@ -2298,7 +2309,10 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n // can only fix caller once this frame is thawed (due to callee saved regs); this happens on the stack _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); } else if (_cont.tail()->has_bitmap() && added_argsize > 0) { - clear_bitmap_bits(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top, added_argsize); + address start = (address)(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top); + int stack_args_slots = f.cb()->as_compiled_method()->method()->num_stack_arg_slots(false /* rounded */); + int argsize_in_bytes = stack_args_slots * VMRegImpl::stack_slot_size; + clear_bitmap_bits(start, start + argsize_in_bytes); } DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);) diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index f4893bae5db..c68180e105b 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -1439,7 +1439,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m assert(sig_index == sizeargs, ""); } int stack_arg_slots = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); - assert(stack_arg_slots == m->num_stack_arg_slots(), ""); + assert(stack_arg_slots == m->num_stack_arg_slots(false /* rounded */), ""); int out_preserve = SharedRuntime::out_preserve_stack_slots(); int sig_index = 0; int arg_index = (m->is_static() ? 0 : -1); diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index 50c93d666e2..3919a89789c 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -487,6 +487,12 @@ HandshakeOperation* HandshakeState::get_op_for_self(bool allow_suspend, bool che assert(_handshakee == Thread::current(), "Must be called by self"); assert(_lock.owned_by_self(), "Lock must be held"); assert(allow_suspend || !check_async_exception, "invalid case"); +#if INCLUDE_JVMTI + if (allow_suspend && _handshakee->is_disable_suspend()) { + // filter out suspend operations while JavaThread is in disable_suspend mode + allow_suspend = false; + } +#endif if (!allow_suspend) { return _queue.peek(no_suspend_no_async_exception_filter); } else if (check_async_exception && !_async_exceptions_blocked) { diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 98b2a569b72..a789988e379 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -440,6 +440,7 @@ JavaThread::JavaThread() : _carrier_thread_suspended(false), _is_in_VTMS_transition(false), _is_in_tmp_VTMS_transition(false), + _is_disable_suspend(false), #ifdef ASSERT _is_VTMS_transition_disabler(false), #endif diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 71bf0cc1d49..fb1355b852a 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -317,6 +317,7 @@ class JavaThread: public Thread { volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition bool _is_in_tmp_VTMS_transition; // thread is in temporary virtual thread mount state transition + bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only #ifdef ASSERT bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions #endif @@ -647,6 +648,9 @@ class JavaThread: public Thread { void set_is_in_VTMS_transition(bool val); void toggle_is_in_tmp_VTMS_transition() { _is_in_tmp_VTMS_transition = !_is_in_tmp_VTMS_transition; }; + bool is_disable_suspend() const { return _is_disable_suspend; } + void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; }; + #ifdef ASSERT bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; } void set_is_VTMS_transition_disabler(bool val); @@ -811,6 +815,7 @@ class JavaThread: public Thread { #if INCLUDE_JVMTI static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); } static ByteSize is_in_tmp_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_tmp_VTMS_transition); } + static ByteSize is_disable_suspend_offset() { return byte_offset_of(JavaThread, _is_disable_suspend); } #endif // Returns the jni environment for this thread diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 9d582b790a1..94d42622c81 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2004,7 +2004,7 @@ void SharedRuntime::check_member_name_argument_is_last_argument(const methodHand assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob"); assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object"); - int comp_args_on_stack = java_calling_convention(sig_bt, regs_without_member_name, total_args_passed - 1); + java_calling_convention(sig_bt, regs_without_member_name, total_args_passed - 1); for (int i = 0; i < member_arg_pos; i++) { VMReg a = regs_with_member_name[i].first(); @@ -3102,7 +3102,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) { BasicType ret_type = si.return_type(); // Now get the compiled-Java arguments layout. - int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed); + SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed); // Generate the compiled-to-native wrapper code nm = SharedRuntime::generate_native_wrapper(&_masm, method, compile_id, sig_bt, regs, ret_type); diff --git a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp index b085bf5fd05..081bdd2e0d3 100644 --- a/src/hotspot/share/runtime/signature.cpp +++ b/src/hotspot/share/runtime/signature.cpp @@ -178,7 +178,6 @@ void Fingerprinter::compute_fingerprint_and_return_type(bool static_flag) { } #if defined(_LP64) && !defined(ZERO) - _stack_arg_slots = align_up(_stack_arg_slots, 2); #ifdef ASSERT int dbg_stack_arg_slots = compute_num_stack_arg_slots(_signature, _param_size, static_flag); assert(_stack_arg_slots == dbg_stack_arg_slots, "fingerprinter: %d full: %d", _stack_arg_slots, dbg_stack_arg_slots); @@ -235,14 +234,17 @@ void Fingerprinter::do_type_calling_convention(BasicType type) { case T_BYTE: case T_SHORT: case T_INT: -#if defined(PPC64) || defined(S390) if (_int_args < Argument::n_int_register_parameters_j) { _int_args++; } else { +#if defined(PPC64) || defined(S390) + _stack_arg_slots += 1; +#else + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 1; +#endif // defined(PPC64) || defined(S390) } break; -#endif // defined(PPC64) || defined(S390) case T_LONG: case T_OBJECT: case T_ARRAY: @@ -250,26 +252,27 @@ void Fingerprinter::do_type_calling_convention(BasicType type) { if (_int_args < Argument::n_int_register_parameters_j) { _int_args++; } else { - PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); - S390_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 2; } break; case T_FLOAT: -#if defined(PPC64) || defined(S390) if (_fp_args < Argument::n_float_register_parameters_j) { _fp_args++; } else { +#if defined(PPC64) || defined(S390) + _stack_arg_slots += 1; +#else + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 1; +#endif // defined(PPC64) || defined(S390) } break; -#endif // defined(PPC64) || defined(S390) case T_DOUBLE: if (_fp_args < Argument::n_float_register_parameters_j) { _fp_args++; } else { - PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); - S390_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 2; } break; diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 851e5139f8a..7401629bf94 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -73,6 +73,7 @@ Thread::Thread() { set_lgrp_id(-1); DEBUG_ONLY(clear_suspendible_thread();) DEBUG_ONLY(clear_indirectly_suspendible_thread();) + DEBUG_ONLY(clear_indirectly_safepoint_thread();) // allocated data structures set_osthread(nullptr); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index cc431e8c900..7461876f378 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -207,6 +207,7 @@ class Thread: public ThreadShadow { private: DEBUG_ONLY(bool _suspendible_thread;) DEBUG_ONLY(bool _indirectly_suspendible_thread;) + DEBUG_ONLY(bool _indirectly_safepoint_thread;) public: // Determines if a heap allocation failure will be retried @@ -225,6 +226,10 @@ class Thread: public ThreadShadow { void set_indirectly_suspendible_thread() { _indirectly_suspendible_thread = true; } void clear_indirectly_suspendible_thread() { _indirectly_suspendible_thread = false; } bool is_indirectly_suspendible_thread() { return _indirectly_suspendible_thread; } + + void set_indirectly_safepoint_thread() { _indirectly_safepoint_thread = true; } + void clear_indirectly_safepoint_thread() { _indirectly_safepoint_thread = false; } + bool is_indirectly_safepoint_thread() { return _indirectly_safepoint_thread; } #endif private: diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index a46101f6d8d..add86b338de 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -1641,6 +1641,19 @@ class ThreadDumper : public CHeapObj { && java_lang_VirtualThread::state(vt) != java_lang_VirtualThread::TERMINATED; } + static bool is_vthread_mounted(oop vt) { + // The code should be consistent with the "mounted virtual thread" case + // (VM_HeapDumper::dump_stack_traces(), ThreadDumper::get_top_frame()). + // I.e. virtual thread is mounted if its carrierThread is not null + // and is_vthread_mounted() for the carrier thread returns true. + oop carrier_thread = java_lang_VirtualThread::carrier_thread(vt); + if (carrier_thread == nullptr) { + return false; + } + JavaThread* java_thread = java_lang_Thread::thread(carrier_thread); + return java_thread->is_vthread_mounted(); + } + ThreadDumper(ThreadType thread_type, JavaThread* java_thread, oop thread_oop); // affects frame_count @@ -1918,7 +1931,10 @@ void HeapObjectDumper::do_object(oop o) { if (o->is_instance()) { // create a HPROF_GC_INSTANCE record for each object DumperSupport::dump_instance(writer(), o, &_class_cache); - if (java_lang_VirtualThread::is_instance(o) && ThreadDumper::should_dump_vthread(o)) { + // If we encounter an unmounted virtual thread it needs to be dumped explicitly + // (mounted virtual threads are dumped with their carriers). + if (java_lang_VirtualThread::is_instance(o) + && ThreadDumper::should_dump_vthread(o) && !ThreadDumper::is_vthread_mounted(o)) { _vthread_dumper->dump_vthread(o, writer()); } } else if (o->is_objArray()) { diff --git a/src/hotspot/share/utilities/copy.cpp b/src/hotspot/share/utilities/copy.cpp index 9ead75f2ceb..ed779796943 100644 --- a/src/hotspot/share/utilities/copy.cpp +++ b/src/hotspot/share/utilities/copy.cpp @@ -243,6 +243,16 @@ void Copy::fill_to_memory_atomic(void* to, size_t size, jubyte value) { } } else { // Not aligned, so no need to be atomic. +#ifdef MUSL_LIBC + // This code is used by Unsafe and may hit the next page after truncation of mapped memory. + // Therefore, we use volatile to prevent compilers from replacing the loop by memset which + // may not trigger SIGBUS as needed (observed on Alpine Linux x86_64) + jbyte fill = value; + for (uintptr_t off = 0; off < size; off += sizeof(jbyte)) { + *(volatile jbyte*)(dst + off) = fill; + } +#else Copy::fill_to_bytes(dst, size, value); +#endif } } diff --git a/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c index 14094e11c45..99dbbcb41d7 100644 --- a/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, 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 @@ -427,6 +427,9 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarInt (JNIEnv *env, jclass cls, jstring jlangtag, jint type) { jint ret = 0; + // Majority of MacOSX fixed locales return Gregorian cal identifier + // Using CFCalendarCopyCurrent() provides a cal that is based off OS settings + // which is more accurate than one created with a Gregorian identifier CFCalendarRef cfcal = CFCalendarCopyCurrent(); if (cfcal != NULL) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index 4278003c465..df76f78bfb5 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -98,6 +98,7 @@ public final class RSACipher extends CipherSpi { // cipher parameter for OAEP padding and TLS RSA premaster secret private AlgorithmParameterSpec spec = null; + private boolean forTlsPremasterSecret = false; // buffer for the data private byte[] buffer; @@ -286,6 +287,7 @@ private void init(int opmode, Key key, SecureRandom random, } spec = params; + forTlsPremasterSecret = true; this.random = random; // for TLS RSA premaster secret } int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 @@ -377,7 +379,7 @@ private byte[] doFinal() throws BadPaddingException, byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false); result = padding.unpad(paddingCopy); - if (result == null) { + if (result == null && !forTlsPremasterSecret) { throw new BadPaddingException ("Padding error in decryption"); } @@ -466,26 +468,22 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, boolean isTlsRsaPremasterSecret = algorithm.equals("TlsRsaPremasterSecret"); - Exception failover = null; byte[] encoded = null; update(wrappedKey, 0, wrappedKey.length); try { encoded = doFinal(); - } catch (BadPaddingException e) { - if (isTlsRsaPremasterSecret) { - failover = e; - } else { - throw new InvalidKeyException("Unwrapping failed", e); - } - } catch (IllegalBlockSizeException e) { - // should not occur, handled with length check above + } catch (BadPaddingException | IllegalBlockSizeException e) { + // BadPaddingException cannot happen for TLS RSA unwrap. + // In that case, padding error is indicated by returning null. + // IllegalBlockSizeException cannot happen in any case, + // because of the length check above. throw new InvalidKeyException("Unwrapping failed", e); } try { if (isTlsRsaPremasterSecret) { - if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + if (!forTlsPremasterSecret) { throw new IllegalStateException( "No TlsRsaPremasterSecretParameterSpec specified"); } @@ -494,7 +492,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, encoded = KeyUtil.checkTlsPreMasterSecretKey( ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), - random, encoded, (failover != null)); + random, encoded, encoded == null); } return ConstructKeys.constructKey(encoded, algorithm, type); diff --git a/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java b/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java index 02e0683a1b9..a9b40d028f5 100644 --- a/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java +++ b/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,10 @@ import java.util.Set; import java.util.stream.Collectors; import static java.lang.StackWalker.Option.*; +import jdk.internal.access.JavaIOPrintStreamAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.InternalLock; +import jdk.internal.vm.Continuation; /** * Helper class to print the virtual thread stack trace when pinned. @@ -42,7 +46,8 @@ * code in that Class. This is used to avoid printing the same stack trace many times. */ class PinnedThreadPrinter { - static final StackWalker STACK_WALKER; + private static final JavaIOPrintStreamAccess JIOPSA = SharedSecrets.getJavaIOPrintStreamAccess(); + private static final StackWalker STACK_WALKER; static { var options = Set.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE); PrivilegedAction pa = () -> @@ -86,45 +91,59 @@ private static int hash(List stack) { } /** - * Prints the continuation stack trace. + * Returns true if the frame is native, a class initializer, or holds monitors. + */ + private static boolean isInterestingFrame(LiveStackFrame f) { + return f.isNativeMethod() + || "".equals(f.getMethodName()) + || (f.getMonitors().length > 0); + } + + /** + * Prints the current thread's stack trace. * * @param printAll true to print all stack frames, false to only print the * frames that are native or holding a monitor */ - static void printStackTrace(PrintStream out, boolean printAll) { + static void printStackTrace(PrintStream out, Continuation.Pinned reason, boolean printAll) { List stack = STACK_WALKER.walk(s -> s.map(f -> (LiveStackFrame) f) .filter(f -> f.getDeclaringClass() != PinnedThreadPrinter.class) .collect(Collectors.toList()) ); + Object lockObj = JIOPSA.lock(out); + if (lockObj instanceof InternalLock lock && lock.tryLock()) { + try { + // find the closest frame that is causing the thread to be pinned + stack.stream() + .filter(f -> isInterestingFrame(f)) + .map(LiveStackFrame::getDeclaringClass) + .findFirst() + .ifPresentOrElse(klass -> { + // print the stack trace if not already seen + int hash = hash(stack); + if (HASHES.get(klass).add(hash)) { + printStackTrace(out, reason, stack, printAll); + } + }, () -> printStackTrace(out, reason, stack, true)); // not found - // find the closest frame that is causing the thread to be pinned - stack.stream() - .filter(f -> (f.isNativeMethod() || f.getMonitors().length > 0)) - .map(LiveStackFrame::getDeclaringClass) - .findFirst() - .ifPresentOrElse(klass -> { - int hash = hash(stack); - Hashes hashes = HASHES.get(klass); - synchronized (hashes) { - // print the stack trace if not already seen - if (hashes.add(hash)) { - printStackTrace(stack, out, printAll); - } - } - }, () -> printStackTrace(stack, out, true)); // not found + } finally { + lock.unlock(); + } + } } - private static void printStackTrace(List stack, - PrintStream out, + private static void printStackTrace(PrintStream out, + Continuation.Pinned reason, + List stack, boolean printAll) { - out.println(Thread.currentThread()); + out.format("%s reason:%s%n", Thread.currentThread(), reason); for (LiveStackFrame frame : stack) { var ste = frame.toStackTraceElement(); int monitorCount = frame.getMonitors().length; if (monitorCount > 0) { out.format(" %s <== monitors:%d%n", ste, monitorCount); - } else if (frame.isNativeMethod() || printAll) { + } else if (printAll || isInterestingFrame(frame)) { out.format(" %s%n", ste); } } diff --git a/src/java.base/share/classes/java/lang/StringBuffer.java b/src/java.base/share/classes/java/lang/StringBuffer.java index ec7ecb5d245..d77462f0c70 100644 --- a/src/java.base/share/classes/java/lang/StringBuffer.java +++ b/src/java.base/share/classes/java/lang/StringBuffer.java @@ -715,6 +715,7 @@ public synchronized StringBuffer reverse() { */ @Override public synchronized StringBuffer repeat(int codePoint, int count) { + toStringCache = null; super.repeat(codePoint, count); return this; } @@ -726,6 +727,7 @@ public synchronized StringBuffer repeat(int codePoint, int count) { */ @Override public synchronized StringBuffer repeat(CharSequence cs, int count) { + toStringCache = null; super.repeat(cs, count); return this; } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 0c100793167..fb2aca379da 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -57,6 +57,7 @@ import java.security.ProtectionDomain; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -813,6 +814,10 @@ public static native void arraycopy(Object src, int srcPos, * Note that even if the security manager does not permit the * {@code getProperties} operation, it may choose to permit the * {@link #getProperty(String)} operation. + *

+ * Additional locale-related system properties defined by the + * {@link Locale##default_locale Default Locale} section in the {@code Locale} + * class description may also be obtained with this method. * * @apiNote * Changing a standard system property may have unpredictable results diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 2707b3ba9bd..6f82516d864 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -191,7 +191,15 @@ private static class VThreadContinuation extends Continuation { protected void onPinned(Continuation.Pinned reason) { if (TRACE_PINNING_MODE > 0) { boolean printAll = (TRACE_PINNING_MODE == 1); - PinnedThreadPrinter.printStackTrace(System.out, printAll); + VirtualThread vthread = (VirtualThread) Thread.currentThread(); + int oldState = vthread.state(); + try { + // avoid printing when in transition states + vthread.setState(RUNNING); + PinnedThreadPrinter.printStackTrace(System.out, reason, printAll); + } finally { + vthread.setState(oldState); + } } } private static Runnable wrap(VirtualThread vthread, Runnable task) { @@ -743,11 +751,16 @@ void unpark() { } } else if ((s == PINNED) || (s == TIMED_PINNED)) { // unpark carrier thread when pinned - synchronized (carrierThreadAccessLock()) { - Thread carrier = carrierThread; - if (carrier != null && ((s = state()) == PINNED || s == TIMED_PINNED)) { - U.unpark(carrier); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + Thread carrier = carrierThread; + if (carrier != null && ((s = state()) == PINNED || s == TIMED_PINNED)) { + U.unpark(carrier); + } } + } finally { + notifyJvmtiDisableSuspend(false); } } } @@ -844,16 +857,21 @@ boolean joinNanos(long nanos) throws InterruptedException { public void interrupt() { if (Thread.currentThread() != this) { checkAccess(); - synchronized (interruptLock) { - interrupted = true; - Interruptible b = nioBlocker; - if (b != null) { - b.interrupt(this); - } + notifyJvmtiDisableSuspend(true); + try { + synchronized (interruptLock) { + interrupted = true; + Interruptible b = nioBlocker; + if (b != null) { + b.interrupt(this); + } - // interrupt carrier thread if mounted - Thread carrier = carrierThread; - if (carrier != null) carrier.setInterrupt(); + // interrupt carrier thread if mounted + Thread carrier = carrierThread; + if (carrier != null) carrier.setInterrupt(); + } + } finally { + notifyJvmtiDisableSuspend(false); } } else { interrupted = true; @@ -872,9 +890,14 @@ boolean getAndClearInterrupt() { assert Thread.currentThread() == this; boolean oldValue = interrupted; if (oldValue) { - synchronized (interruptLock) { - interrupted = false; - carrierThread.clearInterrupt(); + notifyJvmtiDisableSuspend(true); + try { + synchronized (interruptLock) { + interrupted = false; + carrierThread.clearInterrupt(); + } + } finally { + notifyJvmtiDisableSuspend(false); } } return oldValue; @@ -899,11 +922,16 @@ Thread.State threadState() { return Thread.State.RUNNABLE; case RUNNING: // if mounted then return state of carrier thread - synchronized (carrierThreadAccessLock()) { - Thread carrierThread = this.carrierThread; - if (carrierThread != null) { - return carrierThread.threadState(); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + Thread carrierThread = this.carrierThread; + if (carrierThread != null) { + return carrierThread.threadState(); + } } + } finally { + notifyJvmtiDisableSuspend(false); } // runnable, mounted return Thread.State.RUNNABLE; @@ -955,12 +983,12 @@ StackTraceElement[] asyncGetStackTrace() { * Returns null if the thread is mounted or in transition. */ private StackTraceElement[] tryGetStackTrace() { - int initialState = state(); + int initialState = state() & ~SUSPENDED; switch (initialState) { case NEW, STARTED, TERMINATED -> { return new StackTraceElement[0]; // unmounted, empty stack } - case RUNNING, PINNED -> { + case RUNNING, PINNED, TIMED_PINNED -> { return null; // mounted } case PARKED, TIMED_PARKED -> { @@ -972,7 +1000,7 @@ private StackTraceElement[] tryGetStackTrace() { case PARKING, TIMED_PARKING, YIELDING -> { return null; // in transition } - default -> throw new InternalError(); + default -> throw new InternalError("" + initialState); } // thread is unmounted, prevent it from continuing @@ -1019,14 +1047,19 @@ public String toString() { Thread carrier = carrierThread; if (carrier != null) { // include the carrier thread state and name when mounted - synchronized (carrierThreadAccessLock()) { - carrier = carrierThread; - if (carrier != null) { - String stateAsString = carrier.threadState().toString(); - sb.append(stateAsString.toLowerCase(Locale.ROOT)); - sb.append('@'); - sb.append(carrier.getName()); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + carrier = carrierThread; + if (carrier != null) { + String stateAsString = carrier.threadState().toString(); + sb.append(stateAsString.toLowerCase(Locale.ROOT)); + sb.append('@'); + sb.append(carrier.getName()); + } } + } finally { + notifyJvmtiDisableSuspend(false); } } // include virtual thread state when not mounted @@ -1125,6 +1158,9 @@ private void setCarrierThread(Thread carrier) { @JvmtiMountTransition private native void notifyJvmtiHideFrames(boolean hide); + @IntrinsicCandidate + private native void notifyJvmtiDisableSuspend(boolean enter); + private static native void registerNatives(); static { registerNatives(); diff --git a/src/java.base/share/classes/java/lang/foreign/Arena.java b/src/java.base/share/classes/java/lang/foreign/Arena.java index 195f8a44db6..7618fa727a4 100644 --- a/src/java.base/share/classes/java/lang/foreign/Arena.java +++ b/src/java.base/share/classes/java/lang/foreign/Arena.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 @@ -219,6 +219,9 @@ public interface Arena extends SegmentAllocator, AutoCloseable { * Segments allocated with the returned arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. * * @return a new arena that is managed, automatically, by the garbage collector */ @@ -231,6 +234,9 @@ static Arena ofAuto() { * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * Calling {@link #close()} on the returned arena will result in * an {@link UnsupportedOperationException}. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena global() { class Holder { @@ -243,6 +249,9 @@ class Holder { * {@return a new confined arena} Segments allocated with the confined arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread * that created the arena, the arena's owner thread. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena ofConfined() { return MemorySessionImpl.createConfined(Thread.currentThread()).asArena(); @@ -251,6 +260,9 @@ static Arena ofConfined() { /** * {@return a new shared arena} Segments allocated with the global arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena ofShared() { return MemorySessionImpl.createShared().asArena(); diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java index 321d9b09bad..8a2b3b4df30 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -1016,7 +1016,7 @@ static PaddingLayout paddingLayout(long byteSize) { * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0} */ static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) { - MemoryLayoutUtil.requireNonNegative(elementCount); + Utils.checkNonNegativeArgument(elementCount, "elementCount"); Objects.requireNonNull(elementLayout); Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment"); 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 da255b9912b..faf28b01bf0 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -44,6 +44,7 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.MemorySessionImpl; import jdk.internal.foreign.SegmentFactories; +import jdk.internal.foreign.Utils; import jdk.internal.javac.Restricted; import jdk.internal.reflect.CallerSensitive; import jdk.internal.vm.annotation.ForceInline; @@ -1591,6 +1592,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ byte get(ValueLayout.OfByte layout, long offset); @@ -1609,6 +1611,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1629,6 +1632,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ boolean get(ValueLayout.OfBoolean layout, long offset); @@ -1647,6 +1651,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1667,6 +1672,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ char get(ValueLayout.OfChar layout, long offset); @@ -1685,6 +1691,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1705,6 +1712,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ short get(ValueLayout.OfShort layout, long offset); @@ -1723,6 +1731,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1743,6 +1752,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ int get(ValueLayout.OfInt layout, long offset); @@ -1761,6 +1771,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1781,6 +1792,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ float get(ValueLayout.OfFloat layout, long offset); @@ -1799,6 +1811,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1819,6 +1832,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ long get(ValueLayout.OfLong layout, long offset); @@ -1837,6 +1851,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1857,6 +1872,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ double get(ValueLayout.OfDouble layout, long offset); @@ -1875,6 +1891,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1905,6 +1922,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in {@code T} * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ MemorySegment get(AddressLayout layout, long offset); @@ -1923,8 +1941,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is - * {@linkplain #isReadOnly() read-only} + * or {@code offset < 0} * @throws IllegalArgumentException if {@code value} is not a * {@linkplain #isNative() native} segment * @throws IllegalArgumentException if this segment is @@ -1951,6 +1968,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ byte getAtIndex(ValueLayout.OfByte layout, long index); @@ -1973,6 +1991,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ boolean getAtIndex(ValueLayout.OfBoolean layout, long index); @@ -1995,6 +2014,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ char getAtIndex(ValueLayout.OfChar layout, long index); @@ -2017,7 +2037,8 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * or {@code index < 0} + * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfChar layout, long index, char value); @@ -2040,6 +2061,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ short getAtIndex(ValueLayout.OfShort layout, long index); @@ -2061,6 +2083,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfByte layout, long index, byte value); @@ -2084,6 +2107,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value); @@ -2107,6 +2131,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfShort layout, long index, short value); @@ -2130,6 +2155,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ int getAtIndex(ValueLayout.OfInt layout, long index); @@ -2152,6 +2178,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfInt layout, long index, int value); @@ -2175,6 +2202,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ float getAtIndex(ValueLayout.OfFloat layout, long index); @@ -2197,6 +2225,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfFloat layout, long index, float value); @@ -2220,6 +2249,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ long getAtIndex(ValueLayout.OfLong layout, long index); @@ -2242,6 +2272,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfLong layout, long index, long value); @@ -2265,6 +2296,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ double getAtIndex(ValueLayout.OfDouble layout, long index); @@ -2287,6 +2319,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfDouble layout, long index, double value); @@ -2319,6 +2352,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * in {@code T} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ MemorySegment getAtIndex(AddressLayout layout, long index); @@ -2341,7 +2375,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * or {@code index < 0} * @throws IllegalArgumentException if {@code value} is not a {@linkplain #isNative() native} segment * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java index 6be9d949ea6..6c9cf51bee8 100644 --- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java +++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java @@ -33,6 +33,7 @@ import jdk.internal.foreign.ArenaImpl; import jdk.internal.foreign.SlicingAllocator; import jdk.internal.foreign.StringSupport; +import jdk.internal.foreign.Utils; import jdk.internal.vm.annotation.ForceInline; /** @@ -390,9 +391,10 @@ default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) { * with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code source.isAccessibleBy(T) == false} - * @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows + * @throws IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows + * @throws IllegalArgumentException if {@code elementCount < 0} * @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())} - * @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0} + * @throws IndexOutOfBoundsException if {@code sourceOffset < 0} */ @ForceInline default MemorySegment allocateFrom(ValueLayout elementLayout, diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 8fac36fb84f..726fa7c22fc 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -45,6 +45,7 @@ import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; +import java.text.DateFormat; import java.text.MessageFormat; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.LocaleNameProvider; @@ -257,6 +258,74 @@ * locales. For example, {@code Locale.US} is the {@code Locale} object * for the United States. * + *

Default Locale

+ * + *

The default Locale is provided for any locale-sensitive methods if no + * {@code Locale} is explicitly specified as an argument, such as + * {@link DateFormat#getInstance()}. The default Locale is determined at startup + * of the Java runtime and established in the following three phases: + *

    + *
  1. The locale-related system properties listed below are established from the + * host environment. Some system properties (except for {@code user.language}) may + * not have values from the host environment. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Shows property keys and associated values
    Locale-related System Properties KeyDescription
    {@systemProperty user.language}{@link ##def_language language} for the default Locale, + * such as "en" (English)
    {@systemProperty user.script}{@link ##def_script script} for the default Locale, + * such as "Latn" (Latin)
    {@systemProperty user.country}{@link ##def_region country} for the default Locale, + * such as "US" (United States)
    {@systemProperty user.variant}{@link ##def_variant variant} for the default Locale, + * such as "POSIX"
    {@systemProperty user.extensions}{@link ##def_extensions extensions} for the default Locale, + * such as "u-ca-japanese" (Japanese Calendar)
    + *
  2. + *
  3. The values of these system properties can be overridden by values designated + * at startup time. If the overriding value of the {@code user.extensions} property + * is unparsable, it is ignored. The overriding values of other properties are not + * checked for syntax or validity and are used directly in the default Locale. + * (Typically, system property values can be provided using the {@code -D} command-line + * option of a launcher. For example, specifying {@code -Duser.extensions=foobarbaz} + * results in a default Locale with no extensions, while specifying + * {@code -Duser.language=foobarbaz} results in a default Locale whose language is + * "foobarbaz".) + *
  4. + *
  5. The default {@code Locale} instance is constructed from the values of these + * system properties. + *
  6. + *
+ *

Altering the system property values with {@link System#setProperties(Properties)}/ + * {@link System#setProperty(String, String)} has no effect on the default Locale. + *

Once the default Locale is established, applications can query the default + * Locale with {@link #getDefault()} and change it with {@link #setDefault(Locale)}. + * If the default Locale is changed with {@link #setDefault(Locale)}, the corresponding + * system properties are not altered. It is not recommended that applications read + * these system properties and parse or interpret them as their values may be out of date. + * + *

There are finer-grained default Locales specific for each {@link Locale.Category}. + * These category specific default Locales can be queried by {@link #getDefault(Category)}, + * and set by {@link #setDefault(Category, Locale)}. Construction of these category + * specific default Locales are determined by the corresponding system properties, + * which consist of the base system properties as listed above, suffixed by either + * {@code ".display"} or {@code ".format"} depending on the category. For example, + * the value of the {@code user.language.display} system property will be used in the + * {@code language} part of the default Locale for the {@link Locale.Category#DISPLAY} + * category. In the absence of category specific system properties, the "category-less" + * system properties are used, such as {@code user.language} in the previous example. + * *

Locale Matching

* *

If an application or a system is internationalized and provides localized @@ -983,14 +1052,14 @@ public int hashCode() { } /** - * Gets the current value of the default locale for this instance - * of the Java Virtual Machine. + * Gets the current value of the {@link ##default_locale default locale} for + * this instance of the Java Virtual Machine. *

* The Java Virtual Machine sets the default locale during startup * based on the host environment. It is used by many locale-sensitive * methods if no locale is explicitly specified. * It can be changed using the - * {@link #setDefault(java.util.Locale) setDefault} method. + * {@link #setDefault(Locale)} method. * * @return the default locale for this instance of the Java Virtual Machine */ @@ -1000,13 +1069,13 @@ public static Locale getDefault() { } /** - * Gets the current value of the default locale for the specified Category - * for this instance of the Java Virtual Machine. + * Gets the current value of the {@link ##default_locale default locale} for + * the specified Category for this instance of the Java Virtual Machine. *

* The Java Virtual Machine sets the default locale during startup based * on the host environment. It is used by many locale-sensitive methods * if no locale is explicitly specified. It can be changed using the - * setDefault(Locale.Category, Locale) method. + * {@link #setDefault(Locale.Category, Locale)} method. * * @param category the specified category to get the default locale * @throws NullPointerException if category is null @@ -1114,8 +1183,9 @@ private static Optional getDefaultExtensions(String extensions } /** - * Sets the default locale for this instance of the Java Virtual Machine. - * This does not affect the host locale. + * Sets the {@link ##default_locale default locale} for + * this instance of the Java Virtual Machine. This does not affect the + * host locale. *

* If there is a security manager, its {@code checkPermission} * method is called with a {@code PropertyPermission("user.language", "write")} @@ -1148,8 +1218,9 @@ public static synchronized void setDefault(Locale newLocale) { } /** - * Sets the default locale for the specified Category for this instance - * of the Java Virtual Machine. This does not affect the host locale. + * Sets the {@link ##default_locale default locale} for the specified + * Category for this instance of the Java Virtual Machine. This does + * not affect the host locale. *

* If there is a security manager, its checkPermission method is called * with a PropertyPermission("user.language", "write") permission before diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index 5aef5cd12a1..a0d3176c762 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -1143,7 +1143,8 @@ public LinkedTransferQueue(Collection c) { * @throws NullPointerException if the specified element is null */ public void put(E e) { - offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); } /** @@ -1156,7 +1157,9 @@ public void put(E e) { * @throws NullPointerException if the specified element is null */ public boolean offer(E e, long timeout, TimeUnit unit) { - return offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); + return true; } /** @@ -1181,7 +1184,9 @@ public boolean offer(E e) { * @throws NullPointerException if the specified element is null */ public boolean add(E e) { - return offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); + return true; } /** diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index e05027a7abc..7df7fa236c8 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.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 @@ -29,6 +29,7 @@ import java.security.*; import java.security.InvalidAlgorithmParameterException; import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -539,10 +540,19 @@ public static KEM getInstance(String algorithm) List list = GetInstance.getServices( "KEM", Objects.requireNonNull(algorithm, "null algorithm name")); - if (list.isEmpty()) { - throw new NoSuchAlgorithmException(algorithm + " KEM not available"); + List allowed = new ArrayList<>(); + for (Provider.Service s : list) { + if (!JceSecurity.canUseProvider(s.getProvider())) { + continue; + } + allowed.add(s); + } + if (allowed.isEmpty()) { + throw new NoSuchAlgorithmException + (algorithm + " KEM not available"); } - return new KEM(algorithm, new DelayedKEM(list.toArray(new Provider.Service[0]))); + + return new KEM(algorithm, new DelayedKEM(allowed.toArray(new Provider.Service[0]))); } /** @@ -568,7 +578,7 @@ public static KEM getInstance(String algorithm, Provider provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), @@ -601,7 +611,7 @@ public static KEM getInstance(String algorithm, String provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), 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 305594952d4..0efe62c1e4f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -153,9 +153,7 @@ public final MemorySegment reinterpret(Arena arena, Consumer clea public MemorySegment reinterpretInternal(Class callerClass, long newSize, Scope scope, Consumer cleanup) { Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret"); - if (newSize < 0) { - throw new IllegalArgumentException("newSize < 0"); - } + Utils.checkNonNegativeArgument(newSize, "newSize"); if (!isNative()) throw new UnsupportedOperationException("Not a native segment"); Runnable action = cleanup != null ? () -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) : @@ -594,6 +592,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, long elementCount) { + Utils.checkNonNegativeIndex(elementCount, "elementCount"); AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment; AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment; if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) { @@ -625,7 +624,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset, Object dstArray, int dstIndex, int elementCount) { - + Utils.checkNonNegativeIndex(elementCount, "elementCount"); var dstInfo = Utils.BaseAndScale.of(dstArray); if (dstArray.getClass().componentType() != srcLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + srcLayout); @@ -652,7 +651,6 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long sr public static void copy(Object srcArray, int srcIndex, MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset, int elementCount) { - var srcInfo = Utils.BaseAndScale.of(srcArray); if (srcArray.getClass().componentType() != dstLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + dstLayout); diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index d0d5c866f6b..6a081e23eac 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -200,11 +200,8 @@ public static long pointeeByteAlign(AddressLayout addressLayout) { } public static void checkAllocationSizeAndAlign(long byteSize, long byteAlignment) { - // size should be >= 0 - if (byteSize < 0) { - throw new IllegalArgumentException("Invalid allocation size : " + byteSize); - } - + // byteSize should be >= 0 + Utils.checkNonNegativeArgument(byteSize, "allocation size"); checkAlign(byteAlignment); } @@ -216,6 +213,20 @@ public static void checkAlign(long byteAlignment) { } } + @ForceInline + public static void checkNonNegativeArgument(long value, String name) { + if (value < 0) { + throw new IllegalArgumentException("The provided " + name + " is negative: " + value); + } + } + + @ForceInline + public static void checkNonNegativeIndex(long value, String name) { + if (value < 0) { + throw new IndexOutOfBoundsException("The provided " + name + " is negative: " + value); + } + } + private static long computePadding(long offset, long align) { boolean isAligned = offset == 0 || offset % align == 0; if (isAligned) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java index e4d931127af..3c0cf3902bb 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java @@ -151,13 +151,8 @@ private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) { } public long scale(long offset, long index) { - if (offset < 0) { - throw new IllegalArgumentException("Negative offset: " + offset); - } - if (index < 0) { - throw new IllegalArgumentException("Negative index: " + index); - } - + Utils.checkNonNegativeArgument(offset, "offset"); + Utils.checkNonNegativeArgument(index, "index"); return Math.addExact(offset, Math.multiplyExact(byteSize(), index)); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java index dce06141028..6b8e7738198 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java @@ -30,13 +30,6 @@ public final class MemoryLayoutUtil { private MemoryLayoutUtil() { } - public static long requireNonNegative(long value) { - if (value < 0) { - throw new IllegalArgumentException("The provided value was negative: " + value); - } - return value; - } - public static long requireByteSizeValid(long byteSize, boolean allowZero) { if ((byteSize == 0 && !allowZero) || byteSize < 0) { throw new IllegalArgumentException("Invalid byte size: " + byteSize); diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java index 125af069203..b9466074343 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -41,6 +41,7 @@ import java.util.*; import javax.security.auth.x500.X500Principal; +import jdk.internal.misc.ThreadTracker; import sun.security.provider.certpath.PKIX.BuilderParams; import sun.security.util.Debug; import sun.security.x509.AccessDescription; @@ -71,6 +72,10 @@ final class ForwardBuilder extends Builder { TrustAnchor trustAnchor; private final boolean searchAllCertStores; + private static class ThreadTrackerHolder { + static final ThreadTracker AIA_TRACKER = new ThreadTracker(); + } + /** * Initialize the builder with the input parameters. * @@ -336,7 +341,7 @@ private void getMatchingCACerts(ForwardState currentState, } /** - * Download Certificates from the given AIA and add them to the + * Download certificates from the given AIA and add them to the * specified Collection. */ // cs.getCertificates(caSelector) returns a collection of X509Certificate's @@ -348,32 +353,47 @@ private boolean getCerts(AuthorityInfoAccessExtension aiaExt, if (!Builder.USE_AIA) { return false; } + List adList = aiaExt.getAccessDescriptions(); if (adList == null || adList.isEmpty()) { return false; } - boolean add = false; - for (AccessDescription ad : adList) { - CertStore cs = URICertStore.getInstance(ad); - if (cs != null) { - try { - if (certs.addAll((Collection) - cs.getCertificates(caSelector))) { - add = true; - if (!searchAllCertStores) { - return true; + Object key = ThreadTrackerHolder.AIA_TRACKER.tryBegin(); + if (key == null) { + // Avoid recursive fetching of certificates + if (debug != null) { + debug.println("Recursive fetching of certs via the AIA " + + "extension detected"); + } + return false; + } + + try { + boolean add = false; + for (AccessDescription ad : adList) { + CertStore cs = URICertStore.getInstance(ad); + if (cs != null) { + try { + if (certs.addAll((Collection) + cs.getCertificates(caSelector))) { + add = true; + if (!searchAllCertStores) { + return true; + } + } + } catch (CertStoreException cse) { + if (debug != null) { + debug.println("exception getting certs from CertStore:"); + cse.printStackTrace(); } - } - } catch (CertStoreException cse) { - if (debug != null) { - debug.println("exception getting certs from CertStore:"); - cse.printStackTrace(); } } } + return add; + } finally { + ThreadTrackerHolder.AIA_TRACKER.end(key); } - return add; } /** diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java index 059467779b9..c38889ed494 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -291,13 +291,14 @@ public static final boolean isOracleJCEProvider(String providerName) { * contains the lower of that suggested by the client in the client * hello and the highest supported by the server. * @param encoded the encoded key in its "RAW" encoding format - * @param isFailOver whether the previous decryption of the - * encrypted PreMasterSecret message run into problem + * @param failure true if encoded is incorrect according to previous checks * @return the polished PreMasterSecret key in its "RAW" encoding format */ public static byte[] checkTlsPreMasterSecretKey( int clientVersion, int serverVersion, SecureRandom random, - byte[] encoded, boolean isFailOver) { + byte[] encoded, boolean failure) { + + byte[] tmp; if (random == null) { random = JCAUtil.getSecureRandom(); @@ -305,30 +306,38 @@ public static byte[] checkTlsPreMasterSecretKey( byte[] replacer = new byte[48]; random.nextBytes(replacer); - if (!isFailOver && (encoded != null)) { - // check the length - if (encoded.length != 48) { - // private, don't need to clone the byte array. - return replacer; - } - - int encodedVersion = - ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); - if (clientVersion != encodedVersion) { - if (clientVersion > 0x0301 || // 0x0301: TLSv1 - serverVersion != encodedVersion) { - encoded = replacer; - } // Otherwise, For compatibility, we maintain the behavior - // that the version in pre_master_secret can be the - // negotiated version for TLS v1.0 and SSL v3.0. - } + if (failure) { + tmp = replacer; + } else { + tmp = encoded; + } + if (tmp == null) { + encoded = replacer; + } else { + encoded = tmp; + } + // check the length + if (encoded.length != 48) { // private, don't need to clone the byte array. - return encoded; + tmp = replacer; + } else { + tmp = encoded; } - // private, don't need to clone the byte array. - return replacer; + int encodedVersion = + ((tmp[0] & 0xFF) << 8) | (tmp[1] & 0xFF); + int check1 = 0; + int check2 = 0; + int check3 = 0; + if (clientVersion != encodedVersion) check1 = 1; + if (clientVersion > 0x0301) check2 = 1; + if (serverVersion != encodedVersion) check3 = 1; + if ((check1 & (check2 | check3)) == 1) { + return replacer; + } else { + return tmp; + } } /** diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties index 76ad70e34c8..3cbbf15ed02 100644 --- a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties +++ b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -269,6 +269,7 @@ XBB=XBB XBC=XBC XBD=XBD XCD=XCD +XCG=XCG XDR=XDR XFO=XFO XFU=XFU @@ -494,6 +495,7 @@ xbb=European Monetary Unit xbc=European Unit of Account (XBC) xbd=European Unit of Account (XBD) xcd=East Caribbean Dollar +xcg=Caribbean Guilder xdr=Special Drawing Rights xfo=French Gold Franc xfu=French UIC-Franc diff --git a/src/java.base/share/data/currency/CurrencyData.properties b/src/java.base/share/data/currency/CurrencyData.properties index dbfbe799b47..1661b4cccba 100644 --- a/src/java.base/share/data/currency/CurrencyData.properties +++ b/src/java.base/share/data/currency/CurrencyData.properties @@ -32,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=175 +dataVersion=176 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -55,7 +55,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 SRD968-SRG740-SSP728-STD678-STN930-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TMT934-TND788-TOP776-\ TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\ UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ - XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ + XBB956-XBC957-XBD958-XCD951-XCG532-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWL932-\ ZWN942-ZWR935 @@ -189,11 +189,11 @@ CR=CRC # COTE D'IVOIRE CI=XOF # CROATIA -HR=HRK;2022-12-31-23-00-00;EUR +HR=EUR # CUBA CU=CUP # Curaçao -CW=ANG +CW=ANG;2025-04-01-04-00-00;XCG # CYPRUS CY=EUR # CZECHIA @@ -510,7 +510,7 @@ SR=SRD # SVALBARD AND JAN MAYEN SJ=NOK # Sint Maarten (Dutch part) -SX=ANG +SX=ANG;2025-04-01-04-00-00;XCG # ESWATINI SZ=SZL # SWEDEN diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION index 66bd061e8bc..560884d1a82 100644 --- a/src/java.base/share/data/tzdata/VERSION +++ b/src/java.base/share/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2023c +tzdata2023d diff --git a/src/java.base/share/data/tzdata/africa b/src/java.base/share/data/tzdata/africa index a73405fdb01..b4789b16c71 100644 --- a/src/java.base/share/data/tzdata/africa +++ b/src/java.base/share/data/tzdata/africa @@ -308,13 +308,6 @@ Rule Egypt 2007 only - Sep Thu>=1 24:00 0 - # reproduced by other (more accessible) sites[, e.g.,]... # http://elgornal.net/news/news.aspx?id=4699258 -# From Paul Eggert (2014-06-04): -# Sarah El Deeb and Lee Keath of AP report that the Egyptian government says -# the change is because of blackouts in Cairo, even though Ahram Online (cited -# above) says DST had no affect on electricity consumption. There is -# no information about when DST will end this fall. See: -# http://abcnews.go.com/International/wireStory/el-sissi-pushes-egyptians-line-23614833 - # From Steffen Thorsen (2015-04-08): # Egypt will start DST on midnight after Thursday, April 30, 2015. # This is based on a law (no 35) from May 15, 2014 saying it starts the last diff --git a/src/java.base/share/data/tzdata/antarctica b/src/java.base/share/data/tzdata/antarctica index 3de5e726eb4..fc7176cd0d5 100644 --- a/src/java.base/share/data/tzdata/antarctica +++ b/src/java.base/share/data/tzdata/antarctica @@ -103,6 +103,11 @@ # - 2018 Oct 7 4:00 - 2019 Mar 17 3:00 - 2019 Oct 4 3:00 - 2020 Mar 8 3:00 # and now - 2020 Oct 4 0:01 +# From Paul Eggert (2023-12-20): +# Transitions from 2021 on are taken from: +# https://www.timeanddate.com/time/zone/antarctica/casey +# retrieved at various dates. + # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 8:00 - +08 2009 Oct 18 2:00 @@ -116,7 +121,12 @@ Zone Antarctica/Casey 0 - -00 1969 8:00 - +08 2019 Oct 4 3:00 11:00 - +11 2020 Mar 8 3:00 8:00 - +08 2020 Oct 4 0:01 - 11:00 - +11 + 11:00 - +11 2021 Mar 14 0:00 + 8:00 - +08 2021 Oct 3 0:01 + 11:00 - +11 2022 Mar 13 0:00 + 8:00 - +08 2022 Oct 2 0:01 + 11:00 - +11 2023 Mar 9 3:00 + 8:00 - +08 Zone Antarctica/Davis 0 - -00 1957 Jan 13 7:00 - +07 1964 Nov 0 - -00 1969 Feb @@ -263,7 +273,50 @@ Zone Antarctica/Troll 0 - -00 2005 Feb 12 # year-round from 1960/61 to 1992 # Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11 -# See Asia/Urumqi. +# From Craig Mundell (1994-12-15): +# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP +# Vostok, which is one of the Russian stations, is set on the same +# time as Moscow, Russia. +# +# From Lee Hotz (2001-03-08): +# I queried the folks at Columbia who spent the summer at Vostok and this is +# what they had to say about time there: +# "in the US Camp (East Camp) we have been on New Zealand (McMurdo) +# time, which is 12 hours ahead of GMT. The Russian Station Vostok was +# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead +# of GMT). This is a time zone I think two hours east of Moscow. The +# natural time zone is in between the two: 8 hours ahead of GMT." +# +# From Paul Eggert (2001-05-04): +# This seems to be hopelessly confusing, so I asked Lee Hotz about it +# in person. He said that some Antarctic locations set their local +# time so that noon is the warmest part of the day, and that this +# changes during the year and does not necessarily correspond to mean +# solar noon. So the Vostok time might have been whatever the clocks +# happened to be during their visit. So we still don't really know what time +# it is at Vostok. +# +# From Zakhary V. Akulov (2023-12-17 22:00:48 +0700): +# ... from December, 18, 2023 00:00 by my decision the local time of +# the Antarctic research base Vostok will correspond to UTC+5. +# (2023-12-19): We constantly interact with Progress base, with company who +# builds new wintering station, with sledge convoys, with aviation - they all +# use UTC+5. Besides, difference between Moscow time is just 2 hours now, not 4. +# (2023-12-19, in response to the question "Has local time at Vostok +# been UTC+6 ever since 1957, or has it changed before?"): No. At least +# since my antarctic career start, 10 years ago, Vostok base has UTC+7. +# (In response to a 2023-12-18 question "from 02:00 to 00:00 today"): This. +# +# From Paul Eggert (2023-12-18): +# For lack of better info, guess Vostok was at +07 from founding through today, +# except when closed. + +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone Antarctica/Vostok 0 - -00 1957 Dec 16 + 7:00 - +07 1994 Feb + 0 - -00 1994 Nov + 7:00 - +07 2023 Dec 18 2:00 + 5:00 - +05 # S Africa - year-round bases # Marion Island, -4653+03752 diff --git a/src/java.base/share/data/tzdata/asia b/src/java.base/share/data/tzdata/asia index 6a048c3ad28..f86f84b2d27 100644 --- a/src/java.base/share/data/tzdata/asia +++ b/src/java.base/share/data/tzdata/asia @@ -678,7 +678,6 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901 8:00 PRC C%sT # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) -# Vostok base in Antarctica matches this since 1970. Zone Asia/Urumqi 5:50:20 - LMT 1928 6:00 - +06 @@ -3450,6 +3449,9 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # From Heba Hamad (2023-03-22): # ... summer time will begin in Palestine from Saturday 04-29-2023, # 02:00 AM by 60 minutes forward. +# From Heba Hemad (2023-10-09): +# ... winter time will begin in Palestine from Saturday 10-28-2023, +# 02:00 AM by 60 minutes back. # # From Paul Eggert (2023-03-22): # For now, guess that spring and fall transitions will normally @@ -3571,13 +3573,13 @@ Rule Palestine 2070 only - Oct 4 2:00 0 - Rule Palestine 2071 only - Sep 19 2:00 0 - Rule Palestine 2072 only - Sep 10 2:00 0 - Rule Palestine 2072 only - Oct 15 2:00 1:00 S +Rule Palestine 2072 max - Oct Sat<=30 2:00 0 - Rule Palestine 2073 only - Sep 2 2:00 0 - Rule Palestine 2073 only - Oct 7 2:00 1:00 S Rule Palestine 2074 only - Aug 18 2:00 0 - Rule Palestine 2074 only - Sep 29 2:00 1:00 S Rule Palestine 2075 only - Aug 10 2:00 0 - Rule Palestine 2075 only - Sep 14 2:00 1:00 S -Rule Palestine 2075 max - Oct Sat<=30 2:00 0 - Rule Palestine 2076 only - Jul 25 2:00 0 - Rule Palestine 2076 only - Sep 5 2:00 1:00 S Rule Palestine 2077 only - Jul 17 2:00 0 - diff --git a/src/java.base/share/data/tzdata/australasia b/src/java.base/share/data/tzdata/australasia index 893d7055eab..366cfd10cc1 100644 --- a/src/java.base/share/data/tzdata/australasia +++ b/src/java.base/share/data/tzdata/australasia @@ -414,8 +414,14 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov # Please note that there will not be any daylight savings time change # in Fiji for 2022-2023.... # https://www.facebook.com/FijianGovernment/posts/pfbid0mmWVTYmTibn66ybpFda75pDcf34SSpoSaskJW5gXwaKo5Sgc7273Q4fXWc6kQV6Hl + +# From Almaz Mingaleev (2023-10-06): +# Cabinet approved the suspension of Daylight Saving and appropriate +# legislative changes will be considered including the repeal of the +# Daylight Saving Act 1998 +# https://www.fiji.gov.fj/Media-Centre/Speeches/English/CABINET-DECISIONS-3-OCTOBER-2023 # -# From Paul Eggert (2022-10-27): +# From Paul Eggert (2023-10-06): # For now, assume DST is suspended indefinitely. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S diff --git a/src/java.base/share/data/tzdata/backward b/src/java.base/share/data/tzdata/backward index c0746d6dd1b..7ddc6cc3d93 100644 --- a/src/java.base/share/data/tzdata/backward +++ b/src/java.base/share/data/tzdata/backward @@ -228,7 +228,6 @@ Link America/Puerto_Rico America/Tortola Link Pacific/Port_Moresby Antarctica/DumontDUrville Link Pacific/Auckland Antarctica/McMurdo Link Asia/Riyadh Antarctica/Syowa -Link Asia/Urumqi Antarctica/Vostok Link Europe/Berlin Arctic/Longyearbyen Link Asia/Riyadh Asia/Aden Link Asia/Qatar Asia/Bahrain diff --git a/src/java.base/share/data/tzdata/europe b/src/java.base/share/data/tzdata/europe index 446d2e1e658..f1b084f64d0 100644 --- a/src/java.base/share/data/tzdata/europe +++ b/src/java.base/share/data/tzdata/europe @@ -1146,6 +1146,23 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn # 2. The shift *from* DST in 2023 happens as normal, but coincides with the # shift to UTC-02 normaltime (people will not change their clocks here). # 3. After this, DST is still observed, but as -02/-01 instead of -03/-02. +# +# From Múte Bourup Egede via Jógvan Svabo Samuelsen (2023-03-15): +# Greenland will not switch to Daylight Saving Time this year, 2023, +# because the standard time for Greenland will change from UTC -3 to UTC -2. +# However, Greenland will change to Daylight Saving Time again in 2024 +# and onwards. + +# From a contributor who wishes to remain anonymous for now (2023-10-29): +# https://www.dr.dk/nyheder/seneste/i-nat-skal-uret-stilles-en-time-tilbage-men-foerste-gang-sker-det-ikke-i-groenland +# with a link to that page: +# https://naalakkersuisut.gl/Nyheder/2023/10/2710_sommertid +# ... Ittoqqortoormiit joins the time of Nuuk at March 2024. +# What would mean that America/Scoresbysund would either be in -01 year round +# or in -02/-01 like America/Nuuk, but no longer in -01/+00. +# +# From Paul Eggert (2023-10-29): +# For now, assume it will be like America/Nuuk. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Thule 1991 1992 - Mar lastSun 2:00 1:00 D @@ -1166,10 +1183,12 @@ Zone America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit -2:00 - -02 1980 Apr 6 2:00 -2:00 C-Eur -02/-01 1981 Mar 29 - -1:00 EU -01/+00 + -1:00 EU -01/+00 2024 Mar 31 + -2:00 EU -02/-01 Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 2023 Oct 29 1:00u + -3:00 EU -03/-02 2023 Mar 26 1:00u + -2:00 - -02 2023 Oct 29 1:00u -2:00 EU -02/-01 Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT @@ -3734,11 +3753,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 # and not at 3:00 as would have been under EU rules. # This is why I have set the change to EU rules into May 1996, # so that the change in March is stil covered by the Ukraine rule. -# The next change in October 1996 happened under EU rules.... -# TZ database holds three other zones for Ukraine.... I have not yet -# worked out the consequences for these three zones, as we (me and my -# US colleague David Cochrane) are still trying to get more -# information upon these local deviations from Kiev rules. +# The next change in October 1996 happened under EU rules. # # From Paul Eggert (2022-08-27): # For now, assume that Ukraine's zones all followed the same rules, diff --git a/src/java.base/share/data/tzdata/iso3166.tab b/src/java.base/share/data/tzdata/iso3166.tab index cea17732dd1..7fa350ecbe3 100644 --- a/src/java.base/share/data/tzdata/iso3166.tab +++ b/src/java.base/share/data/tzdata/iso3166.tab @@ -26,17 +26,22 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2022-11-18): +# From Paul Eggert (2023-09-06): # This file contains a table of two-letter country codes. Columns are # separated by a single tab. Lines beginning with '#' are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N1087 (2022-09-02). See: Updates on ISO 3166-1 -# https://isotc.iso.org/livelink/livelink/Open/16944257 -# 2. The usual English name for the coded region, -# chosen so that alphabetic sorting of subsets produces helpful lists. -# This is not the same as the English name in the ISO 3166 tables. +# ISO/TC 46 N1108 (2023-04-05). See: ISO/TC 46 Documents +# https://www.iso.org/committee/48750.html?view=documents +# 2. The usual English name for the coded region. This sometimes +# departs from ISO-listed names, sometimes so that sorted subsets +# of names are useful (e.g., "Samoa (American)" and "Samoa +# (western)" rather than "American Samoa" and "Samoa"), +# sometimes to avoid confusion among non-experts (e.g., +# "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"), +# and sometimes to omit needless detail or churn (e.g., "Netherlands" +# rather than "Netherlands (the)" or "Netherlands (Kingdom of the)"). # # The table is sorted by country code. # diff --git a/src/java.base/share/data/tzdata/leapseconds b/src/java.base/share/data/tzdata/leapseconds index 89ce8b89cd2..ab2c1af4bed 100644 --- a/src/java.base/share/data/tzdata/leapseconds +++ b/src/java.base/share/data/tzdata/leapseconds @@ -95,11 +95,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2023 Dec 28 00:00:00 +#Expires 2024 Jun 28 00:00:00 # POSIX timestamps for the data in this file: #updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1703721600 (2023-12-28 00:00:00 UTC) +#expires 1719532800 (2024-06-28 00:00:00 UTC) -# Updated through IERS Bulletin C65 -# File expires on: 28 December 2023 +# Updated through IERS Bulletin C66 +# File expires on: 28 June 2024 diff --git a/src/java.base/share/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica index e240cf35103..b96269a0e26 100644 --- a/src/java.base/share/data/tzdata/northamerica +++ b/src/java.base/share/data/tzdata/northamerica @@ -1,3 +1,4 @@ +# # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -1475,7 +1476,7 @@ Rule StJohns 1989 2006 - Apr Sun>=1 0:01 1:00 D Rule StJohns 2007 2011 - Mar Sun>=8 0:01 1:00 D Rule StJohns 2007 2010 - Nov Sun>=1 0:01 0 S # -# St John's has an apostrophe, but Posix file names can't have apostrophes. +# St John's has an apostrophe, but POSIX file names can't have apostrophes. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/St_Johns -3:30:52 - LMT 1884 -3:30:52 StJohns N%sT 1918 diff --git a/src/java.base/share/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica index 4024e7180cd..da2c6239262 100644 --- a/src/java.base/share/data/tzdata/southamerica +++ b/src/java.base/share/data/tzdata/southamerica @@ -1720,6 +1720,12 @@ Rule Para 2010 2012 - Apr Sun>=8 0:00 0 - # From Carlos Raúl Perasso (2014-02-28): # Decree 1264 can be found at: # http://www.presidencia.gov.py/archivos/documentos/DECRETO1264_ey9r8zai.pdf +# +# From Paul Eggert (2023-07-26): +# Transition dates are now set by Law No. 7115, not by presidential decree. +# https://www.abc.com.py/politica/2023/07/12/promulgacion-el-cambio-de-hora-sera-por-ley/ +# From Carlos Raúl Perasso (2023-07-27): +# http://silpy.congreso.gov.py/descarga/ley-144138 Rule Para 2013 max - Mar Sun>=22 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] diff --git a/src/java.base/share/data/tzdata/zone.tab b/src/java.base/share/data/tzdata/zone.tab index 3edb0d61c80..0a01e8777dd 100644 --- a/src/java.base/share/data/tzdata/zone.tab +++ b/src/java.base/share/data/tzdata/zone.tab @@ -71,7 +71,7 @@ AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) @@ -110,7 +110,7 @@ BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz BQ +120903-0681636 America/Kralendijk BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Para (east); Amapa +BR -0127-04829 America/Belem Para (east), Amapa BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins @@ -130,21 +130,21 @@ BT +2728+08939 Asia/Thimphu BW -2439+02555 Africa/Gaborone BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) -CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) -CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) @@ -230,8 +230,8 @@ HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) -ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) -ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man @@ -378,7 +378,7 @@ RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RW -0157+03004 Africa/Kigali @@ -441,7 +441,7 @@ US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) -US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) US +332654-1120424 America/Phoenix MST - AZ (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c index a0b3e082087..94dbe0b7e37 100644 --- a/src/java.base/share/native/libjava/VirtualThread.c +++ b/src/java.base/share/native/libjava/VirtualThread.c @@ -32,11 +32,12 @@ #define VIRTUAL_THREAD "Ljava/lang/VirtualThread;" static JNINativeMethod methods[] = { - { "notifyJvmtiStart", "()V", (void *)&JVM_VirtualThreadStart }, - { "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd }, - { "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount }, - { "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount }, - { "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames }, + { "notifyJvmtiStart", "()V", (void *)&JVM_VirtualThreadStart }, + { "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd }, + { "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount }, + { "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount }, + { "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames }, + { "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend }, }; JNIEXPORT void JNICALL diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c index a0c427a7e4b..d1ebd3d5b94 100644 --- a/src/java.base/share/native/libverify/check_code.c +++ b/src/java.base/share/native/libverify/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,7 @@ #include #include #include +#include #include "jni.h" #include "jni_util.h" @@ -1195,7 +1196,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) } } if (opcode == JVM_OPC_tableswitch) { - keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1; + keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1; delta = 1; } else { keys = _ck_ntohl(lpc[1]); /* number of pairs */ @@ -1677,11 +1678,14 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) switch (instruction) { case JVM_OPC_tableswitch: { int *lpc = (int *)UCALIGN(iptr + 1); - int index; + int64_t low, high, index; if (lpc + 2 >= (int *)end) { return -1; /* do not read pass the end */ } - index = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]); + low = _ck_ntohl(lpc[1]); + high = _ck_ntohl(lpc[2]); + index = high - low; + // The value of low must be less than or equal to high - i.e. index >= 0 if ((index < 0) || (index > 65535)) { return -1; /* illegal */ } else { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java index da21fb4a511..c8d032109a0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.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 @@ -46,7 +46,7 @@ * @author K Venugopal * @author Sunitha Reddy * - * @LastModified: Nov 2023 + * @LastModified: Jan 2024 */ public class PropertyManager { @@ -184,6 +184,9 @@ public boolean containsProperty(String property) { * @return the value of a property */ public Object getProperty(String property) { + if (XMLInputFactory.SUPPORT_DTD.equals(property)) { + return fSecurityManager.is(XMLSecurityManager.Limit.STAX_SUPPORT_DTD); + } /** * Check to see if the property is managed by the security manager * */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java index 6e5663bfa2c..f922849d5fa 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -94,7 +94,7 @@ * @author K.Venugopal SUN Microsystems * @author Neeraj Bajaj SUN Microsystems * @author Sunitha Reddy SUN Microsystems - * @LastModified: Nov 2023 + * @LastModified: Jan 2024 */ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { @@ -1038,8 +1038,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI } // Step 2: custom catalog if specified - if ((publicId != null || literalSystemId != null) && - staxInputSource == null && (fUseCatalog && fCatalogFile != null)) { + if (staxInputSource == null + && (publicId != null || literalSystemId != null) + && (fUseCatalog && fCatalogFile != null)) { if (fCatalogResolver == null) { fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve); fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures); @@ -1049,8 +1050,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI } // Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue - if ((publicId != null || literalSystemId != null) && - staxInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { + if (staxInputSource == null + && (publicId != null || literalSystemId != null) + && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { initJdkCatalogResolver(); staxInputSource = resolveWithCatalogStAX(fDefCR, JdkCatalog.JDKCATALOG, publicId, literalSystemId); @@ -1061,9 +1063,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI // Note if both publicId and systemId are null, the resolution process continues as usual if (staxInputSource != null) { fISCreatedByResolver = true; - } else if ((publicId == null && literalSystemId == null) || - (JdkXmlUtils.isResolveContinue(fCatalogFeatures) && - fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { + } else if ((publicId == null && literalSystemId == null) + || (JdkXmlUtils.isResolveContinue(fCatalogFeatures) + && fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { staxInputSource = new StaxXMLInputSource( new XMLInputSource(publicId, literalSystemId, baseSystemId, true), false); } @@ -1206,8 +1208,9 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th } // Step 2: custom catalog if specified - if ((publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null) - && xmlInputSource == null && (fUseCatalog && fCatalogFile != null)) { + if (xmlInputSource == null + && (publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null) + && (fUseCatalog && fCatalogFile != null)) { if (fCatalogResolver == null) { fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve); fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures); @@ -1217,8 +1220,9 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th } // Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue - if ((publicId != null || literalSystemId != null) - && xmlInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { + if (xmlInputSource == null + && (publicId != null || literalSystemId != null) + && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) { initJdkCatalogResolver(); // unlike a custom catalog, the JDK Catalog only contains entity references xmlInputSource = resolveEntity(fDefCR, publicId, literalSystemId, baseSystemId); @@ -1226,11 +1230,13 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th // Step 4: default resolution if not resolved by a resolver and the RESOLVE // feature is set to 'continue' - // Note if both publicId and systemId are null, the resolution process continues as usual - if ((publicId == null && literalSystemId == null) || - ((xmlInputSource == null) && JdkXmlUtils.isResolveContinue(fCatalogFeatures) && - fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { - xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false); + if (xmlInputSource == null) { + // Note if both publicId and systemId are null, the resolution process continues as usual + if ((publicId == null && literalSystemId == null) || + (JdkXmlUtils.isResolveContinue(fCatalogFeatures) && + fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) { + xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false); + } } return xmlInputSource; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java index ff4e047d4ca..614bd2fdc99 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -79,7 +79,7 @@ * @author Arnaud Le Hors, IBM * @author Andy Clark, IBM * - * @LastModified: July 2023 + * @LastModified: Jan 2024 */ @SuppressWarnings("deprecation") public abstract class AbstractSAXParser @@ -1831,6 +1831,11 @@ else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) { } */ + // Handle properties managed by XMLSecurityManager + if (featureId.equals(XMLSecurityManager.DISALLOW_DTD)) { + return securityManager.is(XMLSecurityManager.Limit.XERCES_DISALLOW_DTD); + } + return fConfiguration.getFeature(featureId); } catch (XMLConfigurationException e) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 78be89ec1ea..c962862e4bf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -967,6 +967,20 @@ public JCExpression parseType(boolean allowVar, List annotations) return result; } + protected JCExpression parseIntersectionType(int pos, JCExpression firstType) { + JCExpression t = firstType; + int pos1 = pos; + List targets = List.of(t); + while (token.kind == AMP) { + accept(AMP); + targets = targets.prepend(parseType()); + } + if (targets.length() > 1) { + t = toP(F.at(pos1).TypeIntersection(targets.reverse())); + } + return t; + } + public JCExpression unannotatedType(boolean allowVar) { return unannotatedType(allowVar, TYPE); } @@ -1337,15 +1351,7 @@ protected JCExpression term3() { case CAST: accept(LPAREN); selectTypeMode(); - int pos1 = pos; - List targets = List.of(t = parseType()); - while (token.kind == AMP) { - accept(AMP); - targets = targets.prepend(parseType()); - } - if (targets.length() > 1) { - t = toP(F.at(pos1).TypeIntersection(targets.reverse())); - } + t = parseIntersectionType(pos, parseType()); accept(RPAREN); selectExprMode(); JCExpression t1 = term3(); @@ -2853,6 +2859,7 @@ List blockStatement() { case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL: case NULL: case IDENTIFIER: case TRUE: case FALSE: case NEW: case SWITCH: case THIS: case SUPER: + case BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, VOID, BOOLEAN: isYieldStatement = true; break; case PLUSPLUS: case SUBSUB: diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java index ef6fa63e0a6..7b2fb631023 100644 --- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java +++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.security.Key; import java.security.interfaces.*; import java.security.spec.*; +import java.util.Arrays; import javax.crypto.*; import javax.crypto.spec.*; @@ -61,6 +62,9 @@ */ public final class CRSACipher extends CipherSpi { + private static final int ERROR_INVALID_PARAMETER = 0x57; + private static final int NTE_INVALID_PARAMETER = 0x80090027; + // constant for an empty byte array private static final byte[] B0 = new byte[0]; @@ -101,6 +105,8 @@ public final class CRSACipher extends CipherSpi { // cipher parameter for TLS RSA premaster secret private AlgorithmParameterSpec spec = null; + private boolean forTlsPremasterSecret = false; + // the source of randomness private SecureRandom random; @@ -171,6 +177,9 @@ protected void engineInit(int opmode, Key key, } spec = params; this.random = random; // for TLS RSA premaster secret + this.forTlsPremasterSecret = true; + } else { + this.forTlsPremasterSecret = false; } init(opmode, key); } @@ -278,8 +287,7 @@ private void update(byte[] in, int inOfs, int inLen) { } // internal doFinal() method. Here we perform the actual RSA operation - private byte[] doFinal() throws BadPaddingException, - IllegalBlockSizeException { + private byte[] doFinal() throws IllegalBlockSizeException { if (bufOfs > buffer.length) { throw new IllegalBlockSizeException("Data must not be longer " + "than " + (buffer.length - paddingLength) + " bytes"); @@ -308,7 +316,7 @@ private byte[] doFinal() throws BadPaddingException, throw new AssertionError("Internal error"); } - } catch (KeyException e) { + } catch (KeyException | BadPaddingException e) { throw new ProviderException(e); } finally { @@ -331,14 +339,14 @@ protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, // see JCE spec protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) - throws BadPaddingException, IllegalBlockSizeException { + throws IllegalBlockSizeException { update(in, inOfs, inLen); return doFinal(); } // see JCE spec protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, - int outOfs) throws ShortBufferException, BadPaddingException, + int outOfs) throws ShortBufferException, IllegalBlockSizeException { if (outputSize > out.length - outOfs) { throw new ShortBufferException @@ -354,6 +362,7 @@ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, // see JCE spec protected byte[] engineWrap(Key key) throws InvalidKeyException, IllegalBlockSizeException { + byte[] encoded = key.getEncoded(); // TODO - unextractable key if ((encoded == null) || (encoded.length == 0)) { throw new InvalidKeyException("Could not obtain encoded key"); @@ -362,12 +371,7 @@ protected byte[] engineWrap(Key key) throws InvalidKeyException, throw new InvalidKeyException("Key is too long for wrapping"); } update(encoded, 0, encoded.length); - try { - return doFinal(); - } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Wrapping failed", e); - } + return doFinal(); } // see JCE spec @@ -388,31 +392,31 @@ protected java.security.Key engineUnwrap(byte[] wrappedKey, update(wrappedKey, 0, wrappedKey.length); try { encoded = doFinal(); - } catch (BadPaddingException e) { - if (isTlsRsaPremasterSecret) { - failover = e; - } else { - throw new InvalidKeyException("Unwrapping failed", e); - } } catch (IllegalBlockSizeException e) { // should not occur, handled with length check above throw new InvalidKeyException("Unwrapping failed", e); } - if (isTlsRsaPremasterSecret) { - if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { - throw new IllegalStateException( - "No TlsRsaPremasterSecretParameterSpec specified"); + try { + if (isTlsRsaPremasterSecret) { + if (!forTlsPremasterSecret) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + encoded = KeyUtil.checkTlsPreMasterSecretKey( + ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), + ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), + random, encoded, encoded == null); } - // polish the TLS premaster secret - encoded = KeyUtil.checkTlsPreMasterSecretKey( - ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(), - ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(), - random, encoded, (failover != null)); + return constructKey(encoded, algorithm, type); + } finally { + if (encoded != null) { + Arrays.fill(encoded, (byte) 0); + } } - - return constructKey(encoded, algorithm, type); } // see JCE spec @@ -496,17 +500,30 @@ private static Key constructKey(byte[] encodedKey, * Encrypt/decrypt a data buffer using Microsoft Crypto API or CNG. * It expects and returns ciphertext data in big-endian form. */ - private static byte[] encryptDecrypt(byte[] data, int dataSize, - CKey key, boolean doEncrypt) throws KeyException { + private byte[] encryptDecrypt(byte[] data, int dataSize, + CKey key, boolean doEncrypt) throws KeyException, BadPaddingException { + int[] returnStatus = new int[1]; + byte[] result; if (key.getHCryptKey() != 0) { - return encryptDecrypt(data, dataSize, key.getHCryptKey(), doEncrypt); + result = encryptDecrypt(returnStatus, data, dataSize, key.getHCryptKey(), doEncrypt); } else { - return cngEncryptDecrypt(data, dataSize, key.getHCryptProvider(), doEncrypt); + result = cngEncryptDecrypt(returnStatus, data, dataSize, key.getHCryptProvider(), doEncrypt); } + if ((returnStatus[0] == ERROR_INVALID_PARAMETER) || (returnStatus[0] == NTE_INVALID_PARAMETER)) { + if (forTlsPremasterSecret) { + result = null; + } else { + throw new BadPaddingException("Error " + returnStatus[0] + " returned by MSCAPI"); + } + } else if (returnStatus[0] != 0) { + throw new KeyException("Error " + returnStatus[0] + " returned by MSCAPI"); + } + + return result; } - private static native byte[] encryptDecrypt(byte[] data, int dataSize, + private static native byte[] encryptDecrypt(int[] returnStatus, byte[] data, int dataSize, long key, boolean doEncrypt) throws KeyException; - private static native byte[] cngEncryptDecrypt(byte[] data, int dataSize, + private static native byte[] cngEncryptDecrypt(int[] returnStatus, byte[] data, int dataSize, long key, boolean doEncrypt) throws KeyException; } diff --git a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp index f2b6bfd83f6..4787708779d 100644 --- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp +++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp @@ -1905,18 +1905,25 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_destroyKeyContainer /* * Class: sun_security_mscapi_CRSACipher * Method: encryptDecrypt - * Signature: ([BIJZ)[B + * Signature: ([I[BIJZ)[B */ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt - (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey, + (JNIEnv *env, jclass clazz, jintArray jResultStatus, jbyteArray jData, jint jDataSize, jlong hKey, jboolean doEncrypt) { jbyteArray result = NULL; jbyte* pData = NULL; + jbyte* resultData = NULL; DWORD dwDataLen = jDataSize; DWORD dwBufLen = env->GetArrayLength(jData); DWORD i; BYTE tmp; + BOOL success; + DWORD ss = ERROR_SUCCESS; + DWORD lastError = ERROR_SUCCESS; + DWORD resultLen = 0; + DWORD pmsLen = 48; + jbyte pmsArr[48] = {0}; __try { @@ -1943,6 +1950,8 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt pData[i] = pData[dwBufLen - i -1]; pData[dwBufLen - i - 1] = tmp; } + resultData = pData; + resultLen = dwBufLen; } else { // convert to little-endian for (i = 0; i < dwBufLen / 2; i++) { @@ -1952,21 +1961,28 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt } // decrypt - if (! ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated - &dwBufLen)) { - - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; + success = ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated + &dwBufLen); + lastError = GetLastError(); + if (success) { + ss = ERROR_SUCCESS; + resultData = pData; + resultLen = dwBufLen; + } else { + ss = lastError; + resultData = pmsArr; + resultLen = pmsLen; } + env->SetIntArrayRegion(jResultStatus, 0, 1, (jint*) &ss); } - // Create new byte array - if ((result = env->NewByteArray(dwBufLen)) == NULL) { + // Create new byte array + if ((result = env->NewByteArray(resultLen)) == NULL) { __leave; } // Copy data from native buffer to Java buffer - env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData); + env->SetByteArrayRegion(result, 0, resultLen, (jbyte*) resultData); } __finally { @@ -1980,17 +1996,22 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt /* * Class: sun_security_mscapi_CRSACipher * Method: cngEncryptDecrypt - * Signature: ([BIJZ)[B + * Signature: ([I[BIJZ)[B */ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_cngEncryptDecrypt - (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey, + (JNIEnv *env, jclass clazz, jintArray jResultStatus, jbyteArray jData, jint jDataSize, jlong hKey, jboolean doEncrypt) { SECURITY_STATUS ss; jbyteArray result = NULL; jbyte* pData = NULL; + jbyte* resultData = NULL; DWORD dwDataLen = jDataSize; DWORD dwBufLen = env->GetArrayLength(jData); + DWORD resultLen = 0; + DWORD pmsLen = 48; + jbyte pmsArr[48] = {0}; + __try { // Copy data from Java buffer to native buffer @@ -2010,6 +2031,9 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_cngEncryptDecry if (ss != ERROR_SUCCESS) { ThrowException(env, KEY_EXCEPTION, ss); __leave; + } else { + resultLen = dwBufLen; + resultData = pData; } } else { // decrypt @@ -2018,18 +2042,22 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_cngEncryptDecry 0, (PBYTE)pData, dwBufLen, &dwBufLen, NCRYPT_PAD_PKCS1_FLAG); - if (ss != ERROR_SUCCESS) { - ThrowException(env, KEY_EXCEPTION, ss); - __leave; + env->SetIntArrayRegion(jResultStatus, 0, 1, (jint*) &ss); + if (ss == ERROR_SUCCESS) { + resultLen = dwBufLen; + resultData = pData; + } else { + resultLen = pmsLen; + resultData = pmsArr; } - } + } // Create new byte array - if ((result = env->NewByteArray(dwBufLen)) == NULL) { + if ((result = env->NewByteArray(resultLen)) == NULL) { __leave; } // Copy data from native buffer to Java buffer - env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData); + env->SetByteArrayRegion(result, 0, resultLen, (jbyte*) resultData); } __finally { if (pData) { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java index e1e49f22b4c..e47625fb497 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java @@ -88,6 +88,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * the {@code MethodHandles.Lookup} object it carries. This lookup should be used * to find method handles to set as targets of the call site described by this * descriptor. + * @since 9 */ public class CallSiteDescriptor extends SecureLookupSupplier { private final Operation operation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java index eb7de0aba75..23f4f7a8122 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java @@ -141,6 +141,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * in the above example the {@code parseOperation} method is left unimplemented. * * + * @since 9 */ public final class DynamicLinker { private static final String CLASS_NAME = DynamicLinker.class.getName(); diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java index a34cff5ba12..ed211008566 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java @@ -105,6 +105,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@link #setClassLoader(ClassLoader) automatically discovered} ones, and * finally the ones configured with {@link #setFallbackLinkers(List)}; this last * category usually includes {@link BeansLinker}. + * @since 9 */ public final class DynamicLinkerFactory { @SuppressWarnings("removal") diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java index 7563e3946ad..5fe3e96f43e 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java @@ -106,6 +106,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * usually containing the textual representation of the source expression that retrieved the * callee, e.g. {@code StandardOperation.CALL.named("window.open")}. *

+ * @since 9 */ public final class NamedOperation implements Operation { private final Operation baseOperation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java index 69b68d25ffc..8f5e7ede7f6 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java @@ -66,6 +66,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * set of standard namespaces with the {@link StandardNamespace} enum. Operations * that need to specify a namespace they operate on can be expressed using * {@link NamespaceOperation}. + * @since 9 */ public interface Namespace { } diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java index 322767de364..0e047849c2c 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java @@ -134,6 +134,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * StandardNamespace.PROPERTY) * .named("empty"); * + * @since 9 */ public final class NamespaceOperation implements Operation { private final Operation baseOperation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java index bf20c23b738..8842c32c1be 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java @@ -64,6 +64,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Thrown at the invocation if the call site can not be linked by any available {@link GuardingDynamicLinker}. + * @since 9 */ public class NoSuchDynamicMethodException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java index ba22e32c54f..ef0acbc3b57 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java @@ -74,6 +74,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@code GET:PROPERTY|ELEMENT}), and finally we will refer to named operations * by separating the base operation and the name with the colon character (e.g. * {@code GET:PROPERTY|ELEMENT:color}). + * @since 9 */ public interface Operation { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java index 5f74edd700c..e14cfdfebd3 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java @@ -76,6 +76,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * method handles. A relinkable call site will be managed by a * {@link DynamicLinker} object after being associated with it using its * {@link DynamicLinker#link(RelinkableCallSite)} method. + * @since 9 */ public interface RelinkableCallSite { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java b/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java index 73ee39b9002..5ec1f2737fb 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java @@ -32,6 +32,7 @@ /** * Provides security-checked access to a {@code MethodHandles.Lookup} object. * See {@link #getLookup()} for details. + * @since 9 */ public class SecureLookupSupplier { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java index 55b9acee703..b4c33250d38 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java @@ -62,6 +62,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * An enumeration of standard namespaces defined by Dynalink. + * @since 9 */ public enum StandardNamespace implements Namespace { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java index e58bf4e78bf..176a87acd36 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java @@ -67,6 +67,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * disappears from their type signature. * {@link NamedOperation} can also be used to decorate {@link #CALL} and {@link #NEW} operations with a * diagnostic name, and as such it does not affect their type signature. + * @since 9 */ public enum StandardOperation implements Operation { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java index 386f386216c..ca09923292a 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java @@ -135,6 +135,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * property and method names on classes and class instances, as well as access * to per-class linkers using the {@link #getLinkerForClass(Class)} * method.

+ * @since 9 */ public class BeansLinker implements GuardingDynamicLinker { private static final ClassValue linkers = new ClassValue<>() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java index 1fe50b916d9..c1e2f7eb71d 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java @@ -67,6 +67,7 @@ * exception itself, as the linkage for the missing member is often conditional. * * @see BeansLinker#BeansLinker(MissingMemberHandlerFactory) + * @since 9 */ @FunctionalInterface public interface MissingMemberHandlerFactory { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java index 62bb74cb29e..ebd6c7e55e2 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java @@ -102,6 +102,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * constructor. You might want to expose a mechanism in your language for * selecting a constructor with an explicit signature through * {@link BeansLinker#getConstructorMethod(Class, String)}. + * @since 9 */ public final class StaticClass implements Serializable { private static final ClassValue staticClasses = new ClassValue<>() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java index 6c0dd438bbb..267752b0a23 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java @@ -70,10 +70,12 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * specific method with unrelated signatures. In these cases, language runtimes * can be asked to resolve the ambiguity by expressing preferences for one * conversion over the other. + * @since 9 */ public interface ConversionComparator { /** * Enumeration of possible outcomes of comparing one conversion to another. + * @since 9 */ enum Comparison { /** The conversions cannot be compared. **/ diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java index 1a1e23981c5..174e63bff26 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java @@ -86,6 +86,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * throw an exception of the designated type. The guard, the switch points, and * the exception type are all optional (a guarded invocation having none of them * is unconditionally valid). + * @since 9 */ public class GuardedInvocation { private final MethodHandle invocation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java index 6c775022362..fa4f0cd4545 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java @@ -67,6 +67,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * another one. Typical usage is for implementing * {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer) * pre-link transformers}. + * @since 9 */ @FunctionalInterface public interface GuardedInvocationTransformer { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java index c604712ae43..e94cb7b9128 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java @@ -87,6 +87,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Languages can export linkers to other language runtimes for * {@link DynamicLinkerFactory#setClassLoader(ClassLoader) automatic discovery} * using a {@link GuardingDynamicLinkerExporter}. + * @since 9 */ public interface GuardingDynamicLinker { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java index 03be07cf459..cd670a8fdbe 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java @@ -45,6 +45,7 @@ * security manager is present, to ensure that only trusted runtimes can * automatically export their linkers into other runtimes. * @see DynamicLinkerFactory#setClassLoader(ClassLoader) + * @since 9 */ public abstract class GuardingDynamicLinkerExporter implements Supplier> { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java index 981a39059af..bbd327d5bbe 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java @@ -75,6 +75,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * these conversions, will cause more ambiguity for {@link BeansLinker} in * selecting the correct overload when trying to link to an overloaded Java * method. + * @since 9 */ public interface GuardingTypeConverterFactory { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java index 209c1920a3f..1feeed03d15 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java @@ -69,6 +69,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * site. Instances of these requests will be constructed and passed to all * {@link GuardingDynamicLinker} objects managed by the {@link DynamicLinker} * that is trying to link the call site. + * @since 9 */ public interface LinkRequest { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java index e66babebf33..5a028205676 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java @@ -73,6 +73,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Interface for services provided to {@link GuardingDynamicLinker} instances by * the {@link DynamicLinker} that owns them. + * @since 9 */ public interface LinkerServices { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java index 2af6294c517..e9ccd30ffed 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java @@ -68,6 +68,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Typical usage is for implementing * {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer) * internal objects filters}. + * @since 9 */ @FunctionalInterface public interface MethodHandleTransformer { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java index b830e375c12..394f81858ff 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java @@ -70,6 +70,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * of * {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy) * method invocation conversions}. + * @since 9 */ @FunctionalInterface public interface MethodTypeConversionStrategy { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java index 53c1a66e862..1565cfee552 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java @@ -68,6 +68,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * linkers will fall into this category, as they recognize their native objects as Java objects of classes implementing * a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers, * see {@link CompositeTypeBasedGuardingDynamicLinker}. + * @since 9 */ public interface TypeBasedGuardingDynamicLinker extends GuardingDynamicLinker { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java index 8ae1f4754cf..c226a9c0b17 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * A {@link GuardingDynamicLinker} that delegates sequentially to a list of * other guarding dynamic linkers in its * {@link #getGuardedInvocation(LinkRequest, LinkerServices)}. + * @since 9 */ public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java index 184cc8e0ab8..a0805ff57d6 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java @@ -77,6 +77,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * returning true are then bound to the class, and next time a receiver of same * type is encountered, the linking is delegated to those linkers only, speeding * up dispatch. + * @since 9 */ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker { // Using a separate static class instance so there's no strong reference from the class value back to the composite diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java index 9929eeb7e50..7a43f7ebbc0 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java @@ -80,6 +80,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * the parameter filter as being a wrapping method for exposing internal runtime * objects wrapped into an adapter with some public interface, and the return * value filter as being its inverse unwrapping method. + * @since 9 */ public class DefaultInternalObjectFilter implements MethodHandleTransformer { private static final MethodHandle FILTER_VARARGS = new Lookup(MethodHandles.lookup()).findStatic( diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java index 9a456df5ebe..7b0fd0e156b 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Utility methods for creating typical guards for * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)} * and for adjusting their method types. + * @since 9 */ public final class Guards { private static final Logger LOG = Logger diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java index ecf66e7d458..25792f0108b 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * checked exceptions. It is useful in those cases when you're looking up * methods within your own codebase (therefore it is an error if they are not * present). + * @since 9 */ public final class Lookup { private final MethodHandles.Lookup lookup; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java index d8cfd8a9d9c..7a00b9fe3ea 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java @@ -66,6 +66,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Default simple implementation of {@link LinkRequest}. + * @since 9 */ public class SimpleLinkRequest implements LinkRequest { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java index f5ee9e09093..2a3d667d49a 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java @@ -70,6 +70,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Various static utility methods for working with Java types. + * @since 9 */ public final class TypeUtilities { private TypeUtilities() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java index 03c7b9603f6..1218885ae9a 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java @@ -60,5 +60,6 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Contains interfaces and classes that are used to link an {@code invokedynamic} call site. + * @since 9 */ package jdk.dynalink; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java index dbcf3ffd021..84ecfa1db38 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java @@ -75,6 +75,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@link #relink(GuardedInvocation, MethodHandle)} and * {@link #resetAndRelink(GuardedInvocation, MethodHandle)} * methods. + * @since 9 */ public abstract class AbstractRelinkableCallSite extends MutableCallSite implements RelinkableCallSite { private final CallSiteDescriptor descriptor; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java index a026512242a..2f75b53fc3d 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java @@ -84,6 +84,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Race conditions in linking are resolved by throwing away the * {@link GuardedInvocation} produced on the losing thread without incorporating * it into the chain, so it can lead to repeated linking for the same arguments. + * @since 9 */ public class ChainedCallSite extends AbstractRelinkableCallSite { private static final MethodHandle PRUNE_CATCHES; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java index 06f50b4ff80..022d6088d01 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java @@ -71,6 +71,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * If the guard of that single invocation fails, or it has an invalidated * switch point, or its invalidating exception triggered, then the call site * will throw it away and ask its associated {@link DynamicLinker} to relink it. + * @since 9 */ public class SimpleRelinkableCallSite extends AbstractRelinkableCallSite { /** 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 fce80372b1e..6163ef82647 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -292,6 +292,9 @@ public synchronized boolean run(String args[]) { } } expand(); + if (!ok) { + return false; + } if (!moduleInfos.isEmpty()) { // All actual file entries (excl manifest and module-info.class) Set jentries = new HashSet<>(); @@ -338,6 +341,9 @@ public synchronized boolean run(String args[]) { tmpFile = createTemporaryFile("tmpjar", ".jar"); } expand(); + if (!ok) { + return false; + } try (FileInputStream in = (fname != null) ? new FileInputStream(inputFile) : new FileInputStream(FileDescriptor.in); FileOutputStream out = new FileOutputStream(tmpFile); diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index 4157cf600e1..43a3fb4a1f2 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -1,4 +1,4 @@ -.\" 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 @@ -164,42 +164,45 @@ The following \f[I]options\f[R] must be specified using either \f[V]-all\f[R]: (Optional) Show help for all commands (BOOLEAN, false) . .RE .TP -\f[V]Compiler.codecache\f[R] -Prints code cache layout and bounds. +\f[V]Compiler.CodeHeap_Analytics\f[R] [\f[I]function\f[R]] [\f[I]granularity\f[R]] +Print CodeHeap analytics .RS .PP -Impact: Low -.RE -.TP -\f[V]Compiler.codelist\f[R] -Prints all compiled methods in code cache that are alive. -.RS +Impact: Low: Depends on code heap size and content. +Holds CodeCache_lock during analysis step, usually sub-second duration. .PP -Impact: Medium +\f[I]arguments\f[R]: +.IP \[bu] 2 +\f[I]function\f[R]: (Optional) Function to be performed (aggregate, +UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, MethodNames, +discard (STRING, all) +.IP \[bu] 2 +\f[I]granularity\f[R]: (Optional) Detail level - smaller value -> more +detail (INT, 4096) .RE .TP -\f[V]Compiler.perfmap\f[R] (Linux only) -Write map file for Linux perf tool. +\f[V]Compiler.codecache\f[R] +Prints code cache layout and bounds. .RS .PP Impact: Low .RE .TP -\f[V]Compiler.queue\f[R] -Prints methods queued for compilation. +\f[V]Compiler.codelist\f[R] +Prints all compiled methods in code cache that are alive. .RS .PP -Impact: Low +Impact: Medium .RE .TP -\f[V]Compiler.directives_add *filename* *arguments*\f[R] +\f[V]Compiler.directives_add\f[R] \f[I]arguments\f[R] Adds compiler directives from a file. .RS .PP Impact: Low .PP \f[I]arguments\f[R]: -.PP +.IP \[bu] 2 \f[I]filename\f[R]: The name of the directives file (STRING, no default value) .RE @@ -225,6 +228,38 @@ Remove latest added compiler directive. Impact: Low .RE .TP +\f[V]Compiler.memory\f[R] [\f[I]options\f[R]] +Print compilation footprint +.RS +.PP +Impact: Medium: Pause time depends on number of compiled methods +.PP +\f[B]Note:\f[R] +.PP +The \f[I]options\f[R] must be specified using either \f[I]key\f[R] or +\f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-H\f[R]: (Optional) Human readable format (BOOLEAN, false) +.IP \[bu] 2 +\f[V]-s\f[R]: (Optional) Minimum memory size (MEMORY SIZE, 0) +.RE +.TP +\f[V]Compiler.perfmap\f[R] (Linux only) +Write map file for Linux perf tool. +.RS +.PP +Impact: Low +.RE +.TP +\f[V]Compiler.queue\f[R] +Prints methods queued for compilation. +.RS +.PP +Impact: Low +.RE +.TP \f[V]GC.class_histogram\f[R] [\f[I]options\f[R]] Provides statistics about the Java heap usage. .RS @@ -281,6 +316,12 @@ gzipped format using the given compression level. .IP \[bu] 2 \f[V]-overwrite\f[R]: (Optional) If specified, the dump file will be overwritten if it exists (BOOLEAN, false) +.IP \[bu] 2 +\f[V]-parallel\f[R]: (Optional) Number of parallel threads to use for +heap dump. +The VM will try to use the specified number of threads, but might use +fewer. +(INT, 1) .PP \f[I]arguments\f[R]: .IP \[bu] 2 @@ -344,6 +385,11 @@ If no parameters are entered, the current settings are displayed. .PP \f[I]options\f[R]: .IP \[bu] 2 +\f[V]dumppath\f[R]: (Optional) Path to the location where a recording +file is written in case the VM runs into a critical error, such as a +system crash. +(STRING, The default location is the current directory) +.IP \[bu] 2 \f[V]globalbuffercount\f[R]: (Optional) Number of global buffers. This option is a legacy option: change the \f[V]memorysize\f[R] parameter to alter the number of global buffers. @@ -641,7 +687,7 @@ Impact: Low .RE .TP \f[V]JVMTI.data_dump\f[R] -Signals the JVM to do a data-dump request for JVMTI. +Signal the JVM to do a data-dump request for JVMTI. .RS .PP Impact: High @@ -757,8 +803,45 @@ Stops the remote management agent. Impact: Low --- no impact .RE .TP +\f[V]System.dump_map\f[R] [\f[I]options\f[R]] (Linux only) +Dumps an annotated process memory map to an output file. +.RS +.PP +Impact: Low +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-H\f[R]: (Optional) Human readable format (BOOLEAN, false) +.IP \[bu] 2 +\f[V]-F\f[R]: (Optional) File path (STRING, +\[dq]vm_memory_map_.txt\[dq]) +.RE +.TP +\f[V]System.map\f[R] [\f[I]options\f[R]] (Linux only) +Prints an annotated process memory map of the VM process. +.RS +.PP +Impact: Low +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-H\f[R]: (Optional) Human readable format (BOOLEAN, false) +.RE +.TP \f[V]System.native_heap_info\f[R] (Linux only) -Prints information about native heap usage through malloc_info(3). +Attempts to output information regarding native heap usage through +malloc_info(3). +If unsuccessful outputs \[dq]Error: \[dq] and a reason. .RS .PP Impact: Low @@ -771,6 +854,31 @@ Attempts to free up memory by trimming the C-heap. Impact: Low .RE .TP +\f[V]Thread.dump_to_file\f[R] [\f[I]options\f[R]] \f[I]filepath\f[R] +Dump threads, with stack traces, to a file in plain text or JSON format. +.RS +.PP +Impact: Medium: Depends on the number of threads. +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-overwrite\f[R]: (Optional) May overwrite existing file (BOOLEAN, +false) +.IP \[bu] 2 +\f[V]-format\f[R]: (Optional) Output format (\[dq]plain\[dq] or +\[dq]json\[dq]) (STRING, plain) +.PP +\f[I]arguments\f[R]: +.IP \[bu] 2 +\f[V]filepath\f[R]: The file path to the output file (STRING, no default +value) +.RE +.TP \f[V]Thread.print\f[R] [\f[I]options\f[R]] Prints all threads with stacktraces. .RS @@ -792,7 +900,7 @@ false) .RE .TP \f[V]VM.cds\f[R] [\f[I]arguments\f[R]] -Dumps a static or dynamic shared archive that includes all currently +Dump a static or dynamic shared archive that includes all currently loaded classes. .RS .PP @@ -818,78 +926,98 @@ If \f[V]dynamic_dump\f[R] is specified, the target JVM must be started with the JVM option \f[V]-XX:+RecordDynamicDumpInfo\f[R]. .RE .TP -\f[V]VM.classloaders\f[R] [\f[I]options\f[R]] -Prints classloader hierarchy. +\f[V]VM.class_hierarchy\f[R] [\f[I]options\f[R]] [\f[I]arguments\f[R]] +Print a list of all loaded classes, indented to show the class +hierarchy. +The name of each class is followed by the ClassLoaderData* of its +ClassLoader, or \[dq]null\[dq] if it is loaded by the bootstrap class +loader. .RS .PP -Impact: Medium --- Depends on number of class loaders and classes -loaded. +Impact: Medium --- depends on the number of loaded classes. +.PP +\f[B]Note:\f[R] .PP The following \f[I]options\f[R] must be specified using either \f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. .PP \f[I]options\f[R]: .IP \[bu] 2 -\f[V]show-classes\f[R]: (Optional) Print loaded classes. +\f[V]-i\f[R]: (Optional) Inherited interfaces should be printed. (BOOLEAN, false) .IP \[bu] 2 -\f[V]verbose\f[R]: (Optional) Print detailed information. +\f[V]-s\f[R]: (Optional) If a classname is specified, print its +subclasses in addition to its superclasses. +Without this option only the superclasses will be printed. (BOOLEAN, false) +.PP +\f[I]arguments\f[R]: .IP \[bu] 2 -\f[V]fold\f[R]: (Optional) Show loaders of the same name and class as -one. -(BOOLEAN, true) +\f[I]classname\f[R]: (Optional) The name of the class whose hierarchy +should be printed. +If not specified, all class hierarchies are printed. +(STRING, no default value) +.RE +.TP +\f[V]VM.classes\f[R] [\f[I]options\f[R]] +Print all loaded classes +.RS +.PP +Impact: Medium: Depends on number of loaded classes. +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-verbose\f[R]: (Optional) Dump the detailed content of a Java +class. +Some classes are annotated with flags: \f[V]F\f[R] = has, or inherits, a +non-empty finalize method, \f[V]f\f[R] = has final method, \f[V]W\f[R] = +methods rewritten, \f[V]C\f[R] = marked with \f[V]\[at]Contended\f[R] +annotation, \f[V]R\f[R] = has been redefined, \f[V]S\f[R] = is shared +class (BOOLEAN, false) .RE .TP \f[V]VM.classloader_stats\f[R] -Prints statistics about all ClassLoaders. +Print statistics about all ClassLoaders. .RS .PP Impact: Low .RE .TP -\f[V]VM.class_hierarchy\f[R] [\f[I]options\f[R]] [\f[I]arguments\f[R]] -Prints a list of all loaded classes, indented to show the class -hierarchy. -The name of each class is followed by the ClassLoaderData* of its -ClassLoader, or \[dq]null\[dq] if it is loaded by the bootstrap class -loader. +\f[V]VM.classloaders\f[R] [\f[I]options\f[R]] +Prints classloader hierarchy. .RS .PP -Impact: Medium --- depends on the number of loaded classes. -.PP -\f[B]Note:\f[R] +Impact: Medium --- Depends on number of class loaders and classes +loaded. .PP The following \f[I]options\f[R] must be specified using either \f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. .PP \f[I]options\f[R]: .IP \[bu] 2 -\f[V]-i\f[R]: (Optional) Inherited interfaces should be printed. +\f[V]show-classes\f[R]: (Optional) Print loaded classes. (BOOLEAN, false) .IP \[bu] 2 -\f[V]-s\f[R]: (Optional) If a classname is specified, print its -subclasses in addition to its superclasses. -Without this option only the superclasses will be printed. +\f[V]verbose\f[R]: (Optional) Print detailed information. (BOOLEAN, false) -.PP -\f[I]arguments\f[R]: .IP \[bu] 2 -\f[I]classname\f[R]: (Optional) The name of the class whose hierarchy -should be printed. -If not specified, all class hierarchies are printed. -(STRING, no default value) +\f[V]fold\f[R]: (Optional) Show loaders of the same name and class as +one. +(BOOLEAN, true) .RE .TP \f[V]VM.command_line\f[R] -Prints the command line used to start this VM instance. +Print the command line used to start this VM instance. .RS .PP Impact: Low .RE .TP \f[V]VM.dynlibs\f[R] -Prints the loaded dynamic libraries. +Print loaded dynamic libraries. .RS .PP Impact: Low @@ -918,8 +1046,25 @@ If omitted, all events are printed. (STRING, no default value) .RE .TP +\f[V]VM.flags\f[R] [\f[I]options\f[R]] +Print the VM flag options and their current values. +.RS +.PP +Impact: Low +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-all\f[R]: (Optional) Prints all flags supported by the VM +(BOOLEAN, false). +.RE +.TP \f[V]VM.info\f[R] -Prints information about the JVM environment and status. +Print information about the JVM environment and status. .RS .PP Impact: Low @@ -964,23 +1109,6 @@ configuration. (BOOLEAN, no default value) .RE .TP -\f[V]VM.flags\f[R] [\f[I]options\f[R]] -Prints the VM flag options and their current values. -.RS -.PP -Impact: Low -.PP -\f[B]Note:\f[R] -.PP -The following \f[I]options\f[R] must be specified using either -\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. -.PP -\f[I]options\f[R]: -.IP \[bu] 2 -\f[V]-all\f[R]: (Optional) Prints all flags supported by the VM -(BOOLEAN, false). -.RE -.TP \f[V]VM.metaspace\f[R] [\f[I]options\f[R]] Prints the statistics for the metaspace .RS @@ -1015,6 +1143,10 @@ classes for each loader. space. (BOOLEAN, false) .IP \[bu] 2 +\f[V]chunkfreelist\f[R]: (Optional) Shows details about global chunk +free lists (ChunkManager). +(BOOLEAN, false) +.IP \[bu] 2 \f[V]scale\f[R]: (Optional) Memory usage in which to scale. Valid values are: 1, KB, MB or GB (fixed scale) or \[dq]dynamic\[dq] for a dynamically chosen scale. @@ -1022,7 +1154,7 @@ a dynamically chosen scale. .RE .TP \f[V]VM.native_memory\f[R] [\f[I]options\f[R]] -Prints native memory usage +Print native memory usage .RS .PP Impact: Medium @@ -1064,16 +1196,8 @@ purpose. (STRING, KB) .RE .TP -\f[V]VM.print_touched_methods\f[R] -Prints all methods that have ever been touched during the lifetime of -this JVM. -.RS -.PP -Impact: Medium --- depends on Java content. -.RE -.TP \f[V]VM.set_flag\f[R] [\f[I]arguments\f[R]] -Sets the VM flag option by using the provided value. +Sets VM flag option using the provided value. .RS .PP Impact: Low @@ -1088,7 +1212,7 @@ no default value) .RE .TP \f[V]VM.stringtable\f[R] [\f[I]options\f[R]] -Dumps the string table. +Dump string table. .RS .PP Impact: Medium --- depends on the Java content. @@ -1105,7 +1229,7 @@ table (BOOLEAN, false) .RE .TP \f[V]VM.symboltable\f[R] [\f[I]options\f[R]] -Dumps the symbol table. +Dump symbol table. .RS .PP Impact: Medium --- depends on the Java content. @@ -1121,6 +1245,13 @@ The following \f[I]options\f[R] must be specified using either table (BOOLEAN, false) .RE .TP +\f[V]VM.system_properties\f[R] +Print system properties. +.RS +.PP +Impact: Low +.RE +.TP \f[V]VM.systemdictionary\f[R] Prints the statistics for dictionary hashtable sizes and bucket length. .RS @@ -1138,15 +1269,8 @@ The following \f[I]options\f[R] must be specified using either for all class loaders (BOOLEAN, false) . .RE .TP -\f[V]VM.system_properties\f[R] -Prints the system properties. -.RS -.PP -Impact: Low -.RE -.TP \f[V]VM.uptime\f[R] [\f[I]options\f[R]] -Prints the VM uptime. +Print VM uptime. .RS .PP Impact: Low @@ -1163,7 +1287,7 @@ The following \f[I]options\f[R] must be specified using either .RE .TP \f[V]VM.version\f[R] -Prints JVM version information. +Print JVM version information. .RS .PP Impact: Low diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java index 141cf1a932b..8d51cb1de6f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java @@ -63,11 +63,7 @@ private void groupTasksIntoBatches(List tasks) { } for (PeriodicTask task : activeSortedTasks(tasks)) { if (task.isSchedulable()) { - Batch batch = task.getBatch(); - // If new task, or period has changed, find new batch - if (batch == null) { - batch = findBatch(task.getPeriod()); - } + Batch batch = findBatch(task.getPeriod(), task.getBatch()); batch.add(task); } } @@ -89,7 +85,7 @@ private List activeSortedTasks(List unsorted) { return tasks; } - private Batch findBatch(long period) { + private Batch findBatch(long period, Batch oldBatch) { // All events with a period less than 1000 ms // get their own unique batch. The rationale for // this is to avoid a scenario where a user (mistakenly) specifies @@ -102,7 +98,7 @@ private Batch findBatch(long period) { return batch; } } - Batch batch = new Batch(period); + Batch batch = oldBatch != null ? oldBatch : new Batch(period); batches.add(batch); return batch; } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java index 735c969a886..40693b33d6d 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.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 @@ -1827,6 +1827,9 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, // write the class file to the pool as a resource String rn = "/java.base/" + SYSTEM_MODULES_MAP_CLASSNAME + ".class"; + // sort the map of module name to the class name of the generated SystemModules class + List> systemModulesMap = map.entrySet() + .stream().sorted(Map.Entry.comparingByKey()).toList(); ResourcePoolEntry e = ResourcePoolEntry.create(rn, ClassFile.of().build( CD_SYSTEM_MODULES_MAP, clb -> clb.withFlags(ACC_FINAL + ACC_SUPER) @@ -1877,10 +1880,10 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, cob.anewarray(CD_String); int index = 0; - for (String moduleName : sorted(map.keySet())) { + for (Map.Entry entry : systemModulesMap) { cob.dup() // arrayref .constantInstruction(index) - .constantInstruction(moduleName) + .constantInstruction(entry.getKey()) .aastore(); index++; } @@ -1898,10 +1901,10 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, .anewarray(CD_String); int index = 0; - for (String className : sorted(map.values())) { + for (Map.Entry entry : systemModulesMap) { cob.dup() // arrayref .constantInstruction(index) - .constantInstruction(className.replace('/', '.')) + .constantInstruction(entry.getValue().replace('/', '.')) .aastore(); index++; } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh index 730137104cf..27a71ab6161 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh @@ -4,7 +4,8 @@ register_services () { for unit in "$@"; do - systemctl enable --now "$unit" + local unit_name=`basename "$unit"` + systemctl enable --now "$unit_name" done } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java index 1579a48786c..663ca164a3d 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java @@ -190,7 +190,7 @@ static enum TK { EOF(TokenKind.EOF, 0), // ERROR(TokenKind.ERROR, XERRO), // IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM), // - UNDERSCORE(TokenKind.UNDERSCORE, XDECL1), // _ + UNDERSCORE(TokenKind.UNDERSCORE, XDECL1|XEXPR), // _ CLASS(TokenKind.CLASS, XEXPR|XDECL1|XBRACESNEEDED), // class decl (MAPPED: DOTCLASS) MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1), // @ IMPORT(TokenKind.IMPORT, XDECL1|XSTART), // import -- consider declaration diff --git a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index ac777435102..5360e0d517f 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -80,8 +80,13 @@ import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.comp.Resolve; +import com.sun.tools.javac.parser.JavacParser; +import com.sun.tools.javac.parser.Lexer; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.parser.ScannerFactory; +import static com.sun.tools.javac.parser.Tokens.TokenKind.AMP; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -363,7 +368,7 @@ private ParseTask(SourceHandler sh, JavacTaskImpl task, DiagnosticCollector diagnostics, boolean forceExpression) { - super(sh, task, diagnostics); + super(sh, task, diagnostics, false); ReplParserFactory.preRegister(context, forceExpression); cuts = parse(); units = Util.stream(cuts) @@ -402,7 +407,7 @@ class AnalyzeTask extends BaseTask { private AnalyzeTask(SourceHandler sh, JavacTaskImpl task, DiagnosticCollector diagnostics) { - super(sh, task, diagnostics); + super(sh, task, diagnostics, true); cuts = analyze(); } @@ -440,7 +445,7 @@ class CompileTask extends BaseTask { CompileTask(SourceHandlersh, JavacTaskImpl jti, DiagnosticCollector diagnostics) { - super(sh, jti, diagnostics); + super(sh, jti, diagnostics, true); } boolean compile() { @@ -504,11 +509,15 @@ abstract class BaseTask { private BaseTask(SourceHandler sh, JavacTaskImpl task, - DiagnosticCollector diagnostics) { + DiagnosticCollector diagnostics, + boolean analyzeParserFactory) { this.sourceHandler = sh; this.task = task; context = task.getContext(); this.diagnostics = diagnostics; + if (analyzeParserFactory) { + JShellAnalyzeParserFactory.preRegister(context); + } } abstract Iterable cuTrees(); @@ -693,7 +702,7 @@ private void setVariableType(VarSnippet s) { Symtab syms = Symtab.instance(context); Names names = Names.instance(context); Log log = Log.instance(context); - ParserFactory parserFactory = ParserFactory.instance(context); + JShellAnalyzeParserFactory parserFactory = (JShellAnalyzeParserFactory) ParserFactory.instance(context); Attr attr = Attr.instance(context); Enter enter = Enter.instance(context); DisableAccessibilityResolve rs = (DisableAccessibilityResolve) Resolve.instance(context); @@ -709,26 +718,28 @@ private void setVariableType(VarSnippet s) { //ignore any errors: JavaFileObject prev = log.useSource(null); DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log); - try { - //parse the type as a cast, i.e. "() x". This is to support - //intersection types: - CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3); - Parser parser = parserFactory.newParser(buf, false, false, false); - JCExpression expr = parser.parseExpression(); - if (expr.hasTag(Tag.TYPECAST)) { - //if parsed OK, attribute and set the type: - var2OriginalType.put(field, field.type); - - JCTypeCast tree = (JCTypeCast) expr; - rs.runWithoutAccessChecks(() -> { - field.type = attr.attribType(tree.clazz, - enter.getEnvs().iterator().next().enclClass.sym); - }); + parserFactory.runPermitIntersectionTypes(() -> { + try { + //parse the type as a cast, i.e. "() x". This is to support + //intersection types: + CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3); + Parser parser = parserFactory.newParser(buf, false, false, false); + JCExpression expr = parser.parseExpression(); + if (expr.hasTag(Tag.TYPECAST)) { + //if parsed OK, attribute and set the type: + var2OriginalType.put(field, field.type); + + JCTypeCast tree = (JCTypeCast) expr; + rs.runWithoutAccessChecks(() -> { + field.type = attr.attribType(tree.clazz, + enter.getEnvs().iterator().next().enclClass.sym); + }); + } + } finally { + log.popDiagnosticHandler(h); + log.useSource(prev); } - } finally { - log.popDiagnosticHandler(h); - log.useSource(prev); - } + }); } } } @@ -777,4 +788,52 @@ public boolean isAccessible(Env env, Type site, Symbol sym, boolean private static final class Marker {} } + private static final class JShellAnalyzeParserFactory extends ParserFactory { + public static void preRegister(Context context) { + if (context.get(Marker.class) == null) { + context.put(parserFactoryKey, ((Factory) c -> new JShellAnalyzeParserFactory(c))); + context.put(Marker.class, new Marker()); + } + } + + private final ScannerFactory scannerFactory; + private boolean permitIntersectionTypes; + + public JShellAnalyzeParserFactory(Context context) { + super(context); + this.scannerFactory = ScannerFactory.instance(context); + } + + /**Run the given Runnable with intersection type permitted. + * + * @param r Runnnable to run + */ + public void runPermitIntersectionTypes(Runnable r) { + boolean prevPermitIntersectionTypes = permitIntersectionTypes; + try { + permitIntersectionTypes = true; + r.run(); + } finally { + permitIntersectionTypes = prevPermitIntersectionTypes; + } + } + + @Override + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { + com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments); + return new JavacParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, parseModuleInfo) { + @Override + public JCExpression parseType(boolean allowVar, com.sun.tools.javac.util.List annotations) { + int pos = token.pos; + JCExpression t = super.parseType(allowVar, annotations); + if (permitIntersectionTypes) { + t = parseIntersectionType(pos, t); + } + return t; + } + }; + } + + private static final class Marker {} + } } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 01634e28062..19f7b4fa34a 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -64,6 +64,7 @@ compiler/rtm/locking/TestUseRTMXendForLockBusy.java 8183263 generic-x64,generic- compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java 8183263 generic-x64,generic-i586 compiler/c2/Test8004741.java 8235801 generic-all +compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all @@ -85,10 +86,12 @@ gc/epsilon/TestMemoryMXBeans.java 8206434 generic-all gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 generic-all gc/g1/logging/TestG1LoggingFailure.java 8169634 generic-all gc/g1/humongousObjects/TestHeapCounters.java 8178918 generic-all +gc/TestAllocHumongousFragment.java#adaptive 8298781 generic-all +gc/TestAllocHumongousFragment.java#aggressive 8298781 generic-all +gc/TestAllocHumongousFragment.java#iu-aggressive 8298781 generic-all +gc/TestAllocHumongousFragment.java#g1 8298781 generic-all +gc/TestAllocHumongousFragment.java#static 8298781 generic-all gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all -gc/stress/gclocker/TestGCLockerWithParallel.java 8180622 generic-all -gc/stress/gclocker/TestGCLockerWithSerial.java 8180622 generic-all -gc/stress/gclocker/TestGCLockerWithShenandoah.java 8180622 generic-all gc/stress/TestStressG1Humongous.java 8286554 windows-x64 ############################################################################# diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 4573c0ebb9b..27956797948 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -356,7 +356,6 @@ tier2_gc_shenandoah = \ tier3_gc_shenandoah = \ gc/stress/gcold/TestGCOldWithShenandoah.java \ gc/stress/gcbasher/TestGCBasherWithShenandoah.java \ - gc/stress/gclocker/TestGCLockerWithShenandoah.java \ gc/stress/systemgc/TestSystemGCWithShenandoah.java \ gc/shenandoah/TestStringDedupStress.java \ -:tier2_gc_shenandoah diff --git a/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java b/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java new file mode 100644 index 00000000000..d5cdb6bee52 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java @@ -0,0 +1,146 @@ +/* + * 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 8310844 + * @summary Verify that monitors with large offset in the OSR buffer are handled properly. + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,TestLargeMonitorOffset::* TestLargeMonitorOffset + */ + +public class TestLargeMonitorOffset { + + public static void test() { + long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, + l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, + l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, + l31, l32, l33, l34, l35, l36, l37, l38, l39, l40, + l41, l42, l43, l44, l45, l46, l47, l48, l49, l50, + l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, + l71, l72, l73, l74, l75, l76, l77, l78, l79, l80, + l81, l82, l83, l84, l85, l86, l87, l88, l89, l90, + l91, l92, l93, l94, l95, l96, l97, l98, l99, l100, + l101, l102, l103, l104, l105, l106, l107, l108, l109, l110, + l111, l112, l113, l114, l115, l116, l117, l118, l119, l120, + l121, l122, l123, l124, l125, l126, l127, l128, l129, l130, + l131, l132, l133, l134, l135, l136, l137, l138, l139, l140, + l141, l142, l143, l144, l145, l146, l147, l148, l149, l150, + l151, l152, l153, l154, l155, l156, l157, l158, l159, l160, + l161, l162, l163, l164, l165, l166, l167, l168, l169, l170, + l171, l172, l173, l174, l175, l176, l177, l178, l179, l180, + l181, l182, l183, l184, l185, l186, l187, l188, l189, l190, + l191, l192, l193, l194, l195, l196, l197, l198, l199, l200, + l201, l202, l203, l204, l205, l206, l207, l208, l209, l210, + l211, l212, l213, l214, l215, l216, l217, l218, l219, l220, + l221, l222, l223, l224, l225, l226, l227, l228, l229, l230, + l231, l232, l233, l234, l235, l236, l237, l238, l239, l240, + l241, l242, l243, l244, l245, l246, l247, l248, l249, l250, + l251, l252, l253, l254, l255, l256, l257, l258, l259, l260, + l261, l262, l263, l264, l265, l266, l267, l268, l269, l270, + l271, l272, l273, l274, l275, l276, l277, l278, l279, l280, + l281, l282, l283, l284, l285, l286, l287, l288, l289, l290, + l291, l292, l293, l294, l295, l296, l297, l298, l299, l300, + l301, l302, l303, l304, l305, l306, l307, l308, l309, l310, + l311, l312, l313, l314, l315, l316, l317, l318, l319, l320, + l321, l322, l323, l324, l325, l326, l327, l328, l329, l330, + l331, l332, l333, l334, l335, l336, l337, l338, l339, l340, + l341, l342, l343, l344, l345, l346, l347, l348, l349, l350, + l351, l352, l353, l354, l355, l356, l357, l358, l359, l360, + l361, l362, l363, l364, l365, l366, l367, l368, l369, l370, + l371, l372, l373, l374, l375, l376, l377, l378, l379, l380, + l381, l382, l383, l384, l385, l386, l387, l388, l389, l390, + l391, l392, l393, l394, l395, l396, l397, l398, l399, l400, + l401, l402, l403, l404, l405, l406, l407, l408, l409, l410, + l411, l412, l413, l414, l415, l416, l417, l418, l419, l420, + l421, l422, l423, l424, l425, l426, l427, l428, l429, l430, + l431, l432, l433, l434, l435, l436, l437, l438, l439, l440, + l441, l442, l443, l444, l445, l446, l447, l448, l449, l450, + l451, l452, l453, l454, l455, l456, l457, l458, l459, l460, + l461, l462, l463, l464, l465, l466, l467, l468, l469, l470, + l471, l472, l473, l474, l475, l476, l477, l478, l479, l480, + l481, l482, l483, l484, l485, l486, l487, l488, l489, l490, + l491, l492, l493, l494, l495, l496, l497, l498, l499, l500, + l501, l502, l503, l504, l505, l506, l507, l508, l509, l510, + l511, l512, l513, l514, l515, l516, l517, l518, l519, l520, + l521, l522, l523, l524, l525, l526, l527, l528, l529, l530, + l531, l532, l533, l534, l535, l536, l537, l538, l539, l540, + l541, l542, l543, l544, l545, l546, l547, l548, l549, l550, + l551, l552, l553, l554, l555, l556, l557, l558, l559, l560, + l561, l562, l563, l564, l565, l566, l567, l568, l569, l570, + l571, l572, l573, l574, l575, l576, l577, l578, l579, l580, + l581, l582, l583, l584, l585, l586, l587, l588, l589, l590, + l591, l592, l593, l594, l595, l596, l597, l598, l599, l600, + l601, l602, l603, l604, l605, l606, l607, l608, l609, l610, + l611, l612, l613, l614, l615, l616, l617, l618, l619, l620, + l621, l622, l623, l624, l625, l626, l627, l628, l629, l630, + l631, l632, l633, l634, l635, l636, l637, l638, l639, l640, + l641, l642, l643, l644, l645, l646, l647, l648, l649, l650, + l651, l652, l653, l654, l655, l656, l657, l658, l659, l660, + l661, l662, l663, l664, l665, l666, l667, l668, l669, l670, + l671, l672, l673, l674, l675, l676, l677, l678, l679, l680, + l681, l682, l683, l684, l685, l686, l687, l688, l689, l690, + l691, l692, l693, l694, l695, l696, l697, l698, l699, l700, + l701, l702, l703, l704, l705, l706, l707, l708, l709, l710, + l711, l712, l713, l714, l715, l716, l717, l718, l719, l720, + l721, l722, l723, l724, l725, l726, l727, l728, l729, l730, + l731, l732, l733, l734, l735, l736, l737, l738, l739, l740, + l741, l742, l743, l744, l745, l746, l747, l748, l749, l750, + l751, l752, l753, l754, l755, l756, l757, l758, l759, l760, + l761, l762, l763, l764, l765, l766, l767, l768, l769, l770, + l771, l772, l773, l774, l775, l776, l777, l778, l779, l780, + l781, l782, l783, l784, l785, l786, l787, l788, l789, l790, + l791, l792, l793, l794, l795, l796, l797, l798, l799, l800, + l801, l802, l803, l804, l805, l806, l807, l808, l809, l810, + l811, l812, l813, l814, l815, l816, l817, l818, l819, l820, + l821, l822, l823, l824, l825, l826, l827, l828, l829, l830, + l831, l832, l833, l834, l835, l836, l837, l838, l839, l840, + l841, l842, l843, l844, l845, l846, l847, l848, l849, l850, + l851, l852, l853, l854, l855, l856, l857, l858, l859, l860, + l861, l862, l863, l864, l865, l866, l867, l868, l869, l870, + l871, l872, l873, l874, l875, l876, l877, l878, l879, l880, + l881, l882, l883, l884, l885, l886, l887, l888, l889, l890, + l891, l892, l893, l894, l895, l896, l897, l898, l899, l900, + l901, l902, l903, l904, l905, l906, l907, l908, l909, l910, + l911, l912, l913, l914, l915, l916, l917, l918, l919, l920, + l921, l922, l923, l924, l925, l926, l927, l928, l929, l930, + l931, l932, l933, l934, l935, l936, l937, l938, l939, l940, + l941, l942, l943, l944, l945, l946, l947, l948, l949, l950, + l951, l952, l953, l954, l955, l956, l957, l958, l959, l960, + l961, l962, l963, l964, l965, l966, l967, l968, l969, l970, + l971, l972, l973, l974, l975, l976, l977, l978, l979, l980, + l981, l982, l983, l984, l985, l986, l987, l988, l989, l990, + l991, l992, l993, l994, l995, l996, l997, l998, l999, l1000; + + synchronized (TestLargeMonitorOffset.class) { + // Trigger OSR compilation with monitor in the OSR buffer + for (int i = 0; i < 1_000_000; ++i) { + + } + } + } + + public static void main(String[] args) { + test(); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java index eacaa9fca85..9b91375acb7 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.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 @@ -30,6 +30,7 @@ * @bug 8267532 * @summary check that uncommon trap is generated for unhandled catch block * @library /test/lib / + * @requires vm.opt.DeoptimizeALot != true * @run driver compiler.c2.irTests.TestPrunedExHandler */ diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java new file mode 100644 index 00000000000..f97532abfb1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java @@ -0,0 +1,65 @@ +/* + * 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 8323190 + * @summary C2 Segfaults during code generation because of unhandled SafePointScalarMerge monitor debug info. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xcomp -XX:+ReduceAllocationMerges TestInvalidLocation + */ + +public class TestInvalidLocation { + static boolean var2 = true; + static double[] var4 = new double[1]; + + public static void main(String[] args) { + for (int i = 0; i < 10; i++) { + System.out.println(test()); + } + } + + static Class0 test() { + double[] var14; + double var3; + StringBuilder var1 = new StringBuilder(); + Class0 var0 = Class1.Class1_sfield0; + synchronized (var2 ? new StringBuilder() : var1) { + var14 = var4; + for (int i0 = 0; i0 < var0.Class0_field0.length && i0 < var14.length; i0 = 1) { + var3 = var14[i0]; + } + } + return var0; + } + + static class Class0 { + double[] Class0_field0; + Class0() { + Class0_field0 = new double[] { 85.42200639495138 }; + } + } + + class Class1 { + static Class0 Class1_sfield0 = new Class0(); + } +} diff --git a/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java new file mode 100644 index 00000000000..28e4db334f5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java @@ -0,0 +1,210 @@ +/* + * 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=normal + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +/* + * @test id=fuzzer + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch -XX:PerMethodTrapLimit=0 + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +package compiler.splitif; + +public class TestSplitDivThroughPhiWithControl { + static int divisorInt = 34; + static int iFld; + static int x; + static int y; + static long divisorLong = 34L; + static long lFld; + static long lFld2; + static long lFld3; + static boolean flag; + + static int[] iArr = new int[400]; + + public static void main(String[] strArr) { + iArr[0] = 52329; + for (int i = 0; i < 10000; i++) { + flag = i % 3 == 0; // Avoid unstable if trap + divisorInt = i % 2 == 0 ? 0 : 23; // Avoid div by zero trap + divisorLong = divisorInt; // Avoid div by zero trap + try { + testIntDiv(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testIntMod(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongDiv(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongMod(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + testFuzzer(); + } + } + + static void testIntDiv() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; // AddI + int div = (sub / divisorInt); // DivI with AddI input + + if (flag) { + a = y; + } else { + a = 2; + } + // Region + + // Use StoreI with AddI input. Store needs to be split through Region in Split-If which is done together + // with AddI. + iFld = sub; + + if (a < 3) { // If that's split in Split-If + // Use of DivI -> after Split-If, DivI gets a Phi input that merges the split AddI nodes. + // -> triggers assert that we should not find pinned div nodes in cannot_split_division(). + x = div; + } + } + } + + // Same as testIntDiv() but with ModI + static void testIntMod() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; + int mod = (sub % divisorInt); + + if (flag) { + a = y; + } else { + a = 2; + } + + iFld = sub; + + if (a < 3) { + x = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Same as testIntDiv() but with DivL + static void testLongDiv() { + long a; + + for (int j = 0; j < 100; j++) { + y += 5; + long sub = j - 3; + long div = (sub / divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = div; + } + } + } + + + // Same as testIntDiv() but with ModL + static void testLongMod() { + long a; + + for (long j = 0; j < 100; j++) { + lFld2 += 5; + long sub = j - 3; + long mod = (sub % divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Original fuzzer crash + static void testFuzzer() { + int i19, i21 = 4928, i23 = 14; + for (int i = 5; i < 100; i++) { + i19 = i23; + int j = 1; + while (true) { + try { + i21 = (iArr[0] / 34); + i23 = (j % i21); + } catch (ArithmeticException a_e) { + } + iArr = iArr; + iFld = i21; + iArr[1] += 5; + if (j == 1000) { + break; + } + j++; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java b/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java deleted file mode 100644 index 63274b86e72..00000000000 --- a/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ - -/** - * @test - * @bug 8316533 - * @summary Oop of abstract class A with no subclass is subtype checked after null-check - * @run driver compiler.types.TestSubTypeOfAbstractClass - */ - -/** - * @test - * @bug 8316533 - * @summary Oop of abstract class A is subtype checked after null-check - * @requires vm.compiler2.enabled - * @run main/othervm -XX:CompileCommand=compileonly,*A::test - * -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode - * compiler.types.TestSubTypeOfAbstractClass - */ - -package compiler.types; - -public class TestSubTypeOfAbstractClass { - - abstract class A { - public static A get_null() { - return null; - } - - public static boolean test() { - // NullCheck -> CastPP with type A:NotNull - // But A is abstract with no subclass, hence this type is impossible - return get_null() instanceof A; - } - } - - public static void main(String[] args) { - for (int i = 0; i < 10_000; i++ ) { - A.test(); - } - } -} diff --git a/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java b/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java new file mode 100644 index 00000000000..ac94609be34 --- /dev/null +++ b/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java @@ -0,0 +1,78 @@ +/* + * 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 8316756 + * @summary Test UNSAFE.copyMemory in combination with Escape Analysis + * @library /test/lib + * + * @modules java.base/jdk.internal.misc + * + * @run main/othervm -XX:-TieredCompilation -Xbatch -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,compiler.unsafe.UnsafeArrayCopy::test* + * compiler.unsafe.UnsafeArrayCopy + */ + +package compiler.unsafe; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.misc.Unsafe; + + +public class UnsafeArrayCopy { + + private static Unsafe UNSAFE = Unsafe.getUnsafe(); + + static long SRC_BASE = UNSAFE.allocateMemory(4); + static long DST_BASE = UNSAFE.allocateMemory(4); + + static class MyClass { + int x; + } + + static int test() { + MyClass obj = new MyClass(); // Non-escaping to trigger Escape Analysis + UNSAFE.copyMemory(null, SRC_BASE, null, DST_BASE, 4); + obj.x = 42; + return obj.x; + } + + static int[] test2() { + int[] src = new int[4]; + int[] dst = new int[4]; + MyClass obj = new MyClass(); + UNSAFE.copyMemory(src, 0, dst, 0, 4); + obj.x = 42; + dst[1] = obj.x; + return dst; + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; ++i) { + test(); + test2(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java index 0f758be4ed0..a3fcdbaa9b0 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.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 @@ -237,6 +238,17 @@ public double[] vectorMax() { return res; } + @Test + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, + counts = {IRNode.MAX_VD, ">0"}) + public double[] vectorMax_8322090() { + double[] res = new double[SIZE]; + for (int i = 0; i < SIZE; i++) { + res[i] = Math.max(d[i], d[i]); + } + return res; + } + @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, counts = {IRNode.MIN_VD, ">0"}) diff --git a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java index 4c7190ada02..c2448416efa 100644 --- a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java +++ b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java @@ -45,7 +45,7 @@ public static void main(String[] args) throws Exception { "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", - "-XX:G1MixedGCLiveThresholdPercent=20", + "-XX:G1MixedGCLiveThresholdPercent=0", "-Xlog:gc+marking=debug,gc+phases=debug,gc+remset+tracking=trace", "-Xms10M", "-Xmx10M", diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java deleted file mode 100644 index 36b9a59fde6..00000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 gc.stress.gclocker; - -// Stress the GC locker by calling GetPrimitiveArrayCritical while -// concurrently filling up old gen. - -import java.lang.management.MemoryPoolMXBean; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryUsage; -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Queue; - -final class ThreadUtils { - public static void sleep(long durationMS) { - try { - Thread.sleep(durationMS); - } catch (Exception e) { - } - } -} - -class Filler { - private static final int SIZE = 250000; - - private int[] i1 = new int[SIZE]; - private int[] i2 = new int[SIZE]; - private short[] s1 = new short[SIZE]; - private short[] s2 = new short[SIZE]; - - private Map map = new HashMap<>(); - - public Filler() { - for (int i = 0; i < 10000; i++) { - map.put(new Object(), new Object()); - } - } -} - -class Exitable { - private volatile boolean shouldExit = false; - - protected boolean shouldExit() { - return shouldExit; - } - - public void exit() { - shouldExit = true; - } -} - -class MemoryWatcher { - private MemoryPoolMXBean bean; - private final int thresholdPromille = 750; - private final int criticalThresholdPromille = 800; - private final long minGCWaitNanos = 1_000_000_000L; - private final long minFreeWaitElapsedNanos = 30L * 1_000_000_000L; - private final long minFreeCriticalWaitNanos; - - private int lastUsage = 0; - private long lastGCDetectedNanos = System.nanoTime(); - private long lastFreeNanos = System.nanoTime(); - - public MemoryWatcher(String mxBeanName, long minFreeCriticalWaitNanos) { - this.minFreeCriticalWaitNanos = minFreeCriticalWaitNanos; - List memoryBeans = ManagementFactory.getMemoryPoolMXBeans(); - for (MemoryPoolMXBean bean : memoryBeans) { - if (bean.getName().equals(mxBeanName)) { - this.bean = bean; - break; - } - } - } - - private int getMemoryUsage() { - if (bean == null) { - Runtime r = Runtime.getRuntime(); - float free = (float) r.freeMemory() / r.maxMemory(); - return Math.round((1 - free) * 1000); - } else { - MemoryUsage usage = bean.getUsage(); - float used = (float) usage.getUsed() / usage.getCommitted(); - return Math.round(used * 1000); - } - } - - public synchronized boolean shouldFreeUpSpace() { - int usage = getMemoryUsage(); - long nowNanos = System.nanoTime(); - - boolean detectedGC = false; - if (usage < lastUsage) { - lastGCDetectedNanos = nowNanos; - detectedGC = true; - } - - lastUsage = usage; - - long elapsedNanos = nowNanos - lastFreeNanos; - long timeSinceLastGCNanos = nowNanos - lastGCDetectedNanos; - - if (usage > criticalThresholdPromille && elapsedNanos > minFreeCriticalWaitNanos) { - lastFreeNanos = nowNanos; - return true; - } else if (usage > thresholdPromille && !detectedGC) { - if (elapsedNanos > minFreeWaitElapsedNanos || timeSinceLastGCNanos > minGCWaitNanos) { - lastFreeNanos = nowNanos; - return true; - } - } - - return false; - } -} - -class MemoryUser extends Exitable implements Runnable { - private final Queue cache = new ArrayDeque(); - private final MemoryWatcher watcher; - - private void load() { - if (watcher.shouldFreeUpSpace()) { - int toRemove = cache.size() / 5; - for (int i = 0; i < toRemove; i++) { - cache.remove(); - } - } - cache.add(new Filler()); - } - - public MemoryUser(String mxBeanName, long minFreeCriticalWaitNanos) { - watcher = new MemoryWatcher(mxBeanName, minFreeCriticalWaitNanos); - } - - @Override - public void run() { - for (int i = 0; i < 200; i++) { - load(); - } - - while (!shouldExit()) { - load(); - } - } -} - -class GCLockerStresser extends Exitable implements Runnable { - static native void fillWithRandomValues(byte[] array); - - @Override - public void run() { - byte[] array = new byte[1024 * 1024]; - while (!shouldExit()) { - fillWithRandomValues(array); - } - } -} - -public class TestGCLocker { - private static Exitable startGCLockerStresser(String name) { - GCLockerStresser task = new GCLockerStresser(); - - Thread thread = new Thread(task); - thread.setName(name); - thread.setPriority(Thread.MIN_PRIORITY); - thread.start(); - - return task; - } - - private static Exitable startMemoryUser(String mxBeanName, long minFreeCriticalWaitNanos) { - MemoryUser task = new MemoryUser(mxBeanName, minFreeCriticalWaitNanos); - - Thread thread = new Thread(task); - thread.setName("Memory User"); - thread.start(); - - return task; - } - - public static void main(String[] args) { - System.loadLibrary("TestGCLocker"); - - long durationMinutes = args.length > 0 ? Long.parseLong(args[0]) : 5; - String mxBeanName = args.length > 1 ? args[1] : null; - long minFreeCriticalWaitNanos = args.length > 2 - ? Integer.parseInt(args[2]) * 1_000_000L - : 500_000_000L; - - Exitable stresser1 = startGCLockerStresser("GCLockerStresser1"); - Exitable stresser2 = startGCLockerStresser("GCLockerStresser2"); - Exitable memoryUser = startMemoryUser(mxBeanName, minFreeCriticalWaitNanos); - - try { - Thread.sleep(durationMinutes * 60_000L); - } catch (InterruptedException e) { - throw new RuntimeException("Test Failure, did not except an InterruptedException", e); - } - - stresser1.exit(); - stresser2.exit(); - memoryUser.exit(); - } -} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java deleted file mode 100644 index 586fdc79881..00000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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. - * - */ - -package gc.stress.gclocker; - -/* - * @test id=default - * @library / - * @requires vm.gc.Shenandoah - * @summary Stress Shenandoah's JNI handling by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC - * -XX:+ShenandoahVerify - * gc.stress.gclocker.TestGCLockerWithShenandoah - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC - * gc.stress.gclocker.TestGCLockerWithShenandoah - */ - -/* - * @test id=aggressive - * @library / - * @requires vm.gc.Shenandoah - * @summary Stress Shenandoah's JNI handling by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive - * -XX:+ShenandoahOOMDuringEvacALot - * gc.stress.gclocker.TestGCLockerWithShenandoah - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive - * -XX:+ShenandoahAllocFailureALot - * gc.stress.gclocker.TestGCLockerWithShenandoah - */ -public class TestGCLockerWithShenandoah { - public static void main(String[] args) { - String[] testArgs = {"2", "Shenandoah", "0"}; - TestGCLocker.main(testArgs); - } -} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java b/test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java similarity index 59% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java rename to test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java index 9de8fa88ca7..4b1d4fa3867 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java +++ b/test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,22 +19,27 @@ * 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 gc.stress.gclocker; - /* - * @test TestGCLockerWithSerial - * @library / - * @requires vm.gc.Serial - * @requires vm.flavor != "minimal" - * @summary Stress Serial's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseSerialGC gc.stress.gclocker.TestGCLockerWithSerial + * @test + * @bug 8321479 + * @summary VM should not crash with property "-D-D" + * @requires vm.flagless + * @library /test/lib + * @run driver UnrecognizedProperty */ -public class TestGCLockerWithSerial { - public static void main(String[] args) { - String[] testArgs = {"2", "Tenured Gen"}; - TestGCLocker.main(testArgs); + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class UnrecognizedProperty { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-D-D"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Usage: java"); + output.shouldHaveExitValue(1); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java b/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java index b9c2063f3e7..ef13a0a9414 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.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 @@ -199,6 +199,23 @@ public static void createModularJar(String jarPath, createJar(argList); } + public static void createModularJarWithManifest(String jarPath, + String classesDir, + String mainClass, + String manifest) throws Exception { + ArrayList argList = new ArrayList(); + argList.add("--create"); + argList.add("--file=" + jarPath); + if (mainClass != null) { + argList.add("--main-class=" + mainClass); + } + argList.add("--manifest=" + manifest); + argList.add("-C"); + argList.add(classesDir); + argList.add("."); + createJar(argList); + } + private static void createJar(ArrayList args) { if (DEBUG) printIterable("createJar args: ", args); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java new file mode 100644 index 00000000000..9e7579a34fd --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java @@ -0,0 +1,105 @@ +/* + * 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 8322657 + * @summary This test defines an application module using the DefineModuleApp. + * When performing dynamic dump, the modular jar containing the module + * is in the -cp. The jar listed in the "Class-Path" attribute of the modular + * jar doesn't exist. VM should not crash during dynamic dump under this scenario. + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes + * @build jdk.test.whitebox.WhiteBox DefineModuleApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar define_module_app.jar DefineModuleApp + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. ModularJarWithNonExistentJar + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class ModularJarWithNonExistentJar extends DynamicArchiveTestBase { + private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "../jigsaw/modulepath/src"); + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path MANIFEST_PATH = Paths.get(TEST_SRC, "test-classes/manifest-with-non-existent-jar.txt"); + + // the module name of the test module + private static final String TEST_MODULE = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path modularJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE), + MODS_DIR.toString()); + + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + + modularJar = moduleDir.resolve(TEST_MODULE + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + JarBuilder.createModularJarWithManifest(modularJar.toString(), classes, + MAIN_CLASS, MANIFEST_PATH.toString()); + } + + public static void main(String... args) throws Exception { + runTest(ModularJarWithNonExistentJar::testDefaultBase); + } + + static void testDefaultBase() throws Exception { + String topArchiveName = getNewArchiveName("top"); + doTest(topArchiveName); + } + + private static void doTest(String topArchiveName) throws Exception { + // compile the module and create the modular jar file + buildTestModule(); + String appJar = ClassFileInstaller.getJarPath("define_module_app.jar"); + dump(topArchiveName, + "-Xlog:cds,class+path=info", + "-Xlog:cds+dynamic=debug", + "-cp", appJar + File.pathSeparator + modularJar.toString(), + "DefineModuleApp", moduleDir.toString(), TEST_MODULE) + .assertNormalExit(output -> { + output.shouldContain("Written dynamic archive 0x"); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java new file mode 100644 index 00000000000..fad62598cc7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java @@ -0,0 +1,51 @@ +/* + * 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 app defines a module using the ModuleLayer.defineModulesWithOneLoader API + * which calls the JVM_DefineModule. + **/ + +import java.nio.file.Path; +import java.lang.ModuleLayer.Controller; +import java.lang.module.*; +import java.util.List; +import java.util.Set; + +public class DefineModuleApp { + public static void main(String[] args) throws Throwable { + if (args.length != 2) { + throw new RuntimeException("DefineModuleApp expects 2 args but saw " + args.length); + } + final Path MODS = Path.of(args[0]); + final String MODULE_NAME = args[1]; + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(ModuleFinder.of(), ModuleFinder.of(MODS), Set.of(MODULE_NAME)); + ResolvedModule m = cf.findModule(MODULE_NAME).orElseThrow(); + ModuleLayer bootLayer = ModuleLayer.boot(); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Controller controller = ModuleLayer.defineModulesWithOneLoader(cf, List.of(bootLayer), scl); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt new file mode 100644 index 00000000000..7558b8b2c82 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: NonExistent.jar +Created-By: 23-internal (Oracle Corporation) diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm similarity index 63% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java rename to test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm index a70a35daa63..24c53f2032d 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, 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 @@ -21,19 +21,23 @@ * questions. * */ - -package gc.stress.gclocker; - /* - * @test TestGCLockerWithG1 - * @library / - * @requires vm.gc.G1 - * @summary Stress G1's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseG1GC gc.stress.gclocker.TestGCLockerWithG1 + * This is a non-abstract class with an abstract method. + * */ -public class TestGCLockerWithG1 { - public static void main(String[] args) { - String[] testArgs = {"2", "G1 Old Gen"}; - TestGCLocker.main(testArgs); +super public class AbstractMethodClass + extends java/lang/Object + version 51:0 // Java 7 version +{ + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; } + + public abstract Method "abstractM":"()V"; + } diff --git a/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java b/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java new file mode 100644 index 00000000000..2384f6d5aef --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java @@ -0,0 +1,68 @@ +/* + * 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 8323243 + * @summary Test that invocation of an abstract method from JNI works correctly + * @compile AbstractMethodClass.jasm + * @run main/othervm/native TestJNIAbstractMethod + */ + +/** + * We are testing invocation of an abstract method from JNI - which should + * simply result in throwning AbstractMethodError. To invoke an abstract method + * we must have an instance method (as abstract static methods are illegal), + * but instantiating an abstract class is also illegal at the Java language + * level, so we have to use a custom jasm class that contains an abstract method + * declaration, but which is not itself declared as an abstract class. + */ +public class TestJNIAbstractMethod { + + // Invokes an abstract method from JNI and throws AbstractMethodError. + private static native void invokeAbstractM(Class AMclass, + AbstractMethodClass receiver); + + static { + System.loadLibrary("JNIAbstractMethod"); + } + + public static void main(String[] args) { + AbstractMethodClass obj = new AbstractMethodClass(); + try { + System.out.println("Attempting direct invocation via Java"); + obj.abstractM(); + throw new RuntimeException("Did not get AbstractMethodError from Java!"); + } catch (AbstractMethodError expected) { + System.out.println("ok - got expected exception: " + expected); + } + try { + System.out.println("Attempting direct invocation via JNI"); + invokeAbstractM(obj.getClass(), obj); + throw new RuntimeException("Did not get AbstractMethodError from JNI!"); + } catch (AbstractMethodError expected) { + System.out.println("ok - got expected exception: " + expected); + } + } +} diff --git a/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c new file mode 100644 index 00000000000..35a28f7029a --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c @@ -0,0 +1,43 @@ +/* + * 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 +#include +#include + +JNIEXPORT void JNICALL Java_TestJNIAbstractMethod_invokeAbstractM(JNIEnv* env, + jclass this_cls, + jclass target_cls, + jobject receiver) { + + jmethodID mid = (*env)->GetMethodID(env, target_cls, "abstractM", "()V"); + if (mid == NULL) { + fprintf(stderr, "Error looking up method abstractM\n"); + (*env)->ExceptionDescribe(env); + exit(1); + } + + printf("Invoking abstract method ...\n"); + (*env)->CallVoidMethod(env, receiver, mid); // Should raise exception + +} diff --git a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java index e4ad27b46e5..a94d9af4c27 100644 --- a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java +++ b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java @@ -350,7 +350,7 @@ public RangeWithPageSize(String start, String end, String pageSize, String thpEl this.start = Long.parseUnsignedLong(start, 16); this.end = Long.parseUnsignedLong(end, 16); this.pageSize = Long.parseLong(pageSize); - this.thpEligible = Integer.parseInt(thpEligible) == 1; + this.thpEligible = thpEligible == null ? false : (Integer.parseInt(thpEligible) == 1); vmFlagHG = false; vmFlagHT = false; @@ -365,12 +365,11 @@ public RangeWithPageSize(String start, String end, String pageSize, String thpEl } } - // When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false. - // Check the THPeligible property instead. - isTHP = !vmFlagHT && this.thpEligible; + // When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false, + // therefore also check thpEligible. If this is still causing problems in the future, + // we might have to check the AnonHugePages field. - // vmFlagHG should imply isTHP - assert !vmFlagHG || isTHP; + isTHP = vmFlagHG || this.thpEligible; } public long getPageSize() { diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java index 7fe5abb800f..2243a1d37b6 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java @@ -26,7 +26,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -223,11 +225,22 @@ private static void verifyDump(File dumpFile) throws Exception { // Log all threads with stack traces and stack references. List threads = snapshot.getThreads(); List roots = Collections.list(snapshot.getRoots()); + // And detect thread object duplicates. + Set uniqueThreads = new HashSet<>(); + log("Threads:"); for (ThreadObject thread: threads) { + JavaHeapObject threadObj = snapshot.findThing(thread.getId()); + JavaClass threadClass = threadObj.getClazz(); StackTrace st = thread.getStackTrace(); StackFrame[] frames = st.getFrames(); - log("thread " + thread.getIdString() + ", " + frames.length + " frames"); + log("thread " + thread.getIdString() + " (" + threadClass.getName() + "), " + frames.length + " frames"); + + if (uniqueThreads.contains(thread.getId())) { + log(" - ERROR: duplicate"); + } else { + uniqueThreads.add(thread.getId()); + } List stackRoots = findStackRoot(roots, thread); for (int i = 0; i < frames.length; i++) { @@ -250,6 +263,10 @@ private static void verifyDump(File dumpFile) throws Exception { } } + if (threads.size() != uniqueThreads.size()) { + throw new RuntimeException("Thread duplicates detected (" + (threads.size() - uniqueThreads.size()) + ")"); + } + // Verify objects from thread stacks are dumped. test(snapshot, VThreadInHeapDumpTarg.VThreadMountedReferenced.class); test(snapshot, VThreadInHeapDumpTarg.PThreadReferenced.class); diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java new file mode 100644 index 00000000000..d679f382d93 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test id=default + * @summary Do not suspend virtual threads in a critical section. + * @bug 8311218 + * @requires vm.continuations + * @library /testlibrary + * @run main/othervm SuspendWithInterruptLock + */ + +/** + * @test id=xint + * @summary Do not suspend virtual threads in a critical section. + * @bug 8311218 + * @requires vm.continuations + * @library /testlibrary + * @run main/othervm -Xint SuspendWithInterruptLock + */ + +import jvmti.JVMTIUtils; + +public class SuspendWithInterruptLock { + static volatile boolean done; + + public static void main(String[] args) throws Exception { + Thread yielder = Thread.ofVirtual().name("yielder").start(() -> yielder()); + Thread stateReader = Thread.ofVirtual().name("stateReader").start(() -> stateReader(yielder)); + Thread suspender = new Thread(() -> suspender(stateReader)); + suspender.start(); + + yielder.join(); + stateReader.join(); + suspender.join(); + } + + static private void yielder() { + int iterations = 100_000; + while (iterations-- > 0) { + Thread.yield(); + } + done = true; + } + + static private void stateReader(Thread target) { + while (!done) { + target.getState(); + } + } + + static private void suspender(Thread target) { + while (!done) { + suspendThread(target); + sleep(1); + resumeThread(target); + // Allow progress + sleep(5); + } + } + + static void suspendThread(Thread t) { + try { + JVMTIUtils.suspendThread(t); + } catch (JVMTIUtils.JvmtiException e) { + if (e.getCode() != JVMTIUtils.JVMTI_ERROR_THREAD_NOT_ALIVE) { + throw e; + } + } + } + + static void resumeThread(Thread t) { + try { + JVMTIUtils.resumeThread(t); + } catch (JVMTIUtils.JvmtiException e) { + if (e.getCode() != JVMTIUtils.JVMTI_ERROR_THREAD_NOT_ALIVE) { + throw e; + } + } + } + + static private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) {} + } +} + diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java new file mode 100644 index 00000000000..442f13f4927 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java @@ -0,0 +1,201 @@ +/* + * 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 common.catalog; + +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.SAXException; + +import javax.xml.catalog.CatalogFeatures; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.SchemaFactory; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.catalog.CatalogManager.catalogResolver; +import javax.xml.catalog.CatalogResolver; +import javax.xml.validation.Validator; +import org.testng.annotations.Test; + +/* + * @test + * @bug 8323571 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng common.catalog.NullIdTest + * @summary Verifies null values are handled properly in the source resolution + * process. + */ +public class NullIdTest { + private static final Map SCHEMAS; + // Source Level JDK 8 + static { + Map map = new HashMap<>(); + map.put("https://schemas.opentest4j.org/reporting/events/0.1.0", "events.xsd"); + map.put("https://schemas.opentest4j.org/reporting/core/0.1.0", "core.xsd"); + SCHEMAS = Collections.unmodifiableMap(map); + } + + /* + * Verifies that the source resolution process recognizes the custom InputSource + * correctly even though the public and system IDs are null. + */ + @Test + public void test() throws Exception { + String xml = ""; + validate(new StreamSource(new StringReader(xml))); + System.out.println("Successfully validated"); + } + + private static void validate(Source source) throws SAXException, IOException { + SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + Validator validator = schemaFactory.newSchema().newValidator(); + validator.setResourceResolver(createResourceResolver()); + validator.validate(source); + } + + private static LSResourceResolver createResourceResolver() { + return (type, namespaceURI, publicId, systemId, baseURI) -> { + if (namespaceURI != null) { + if (SCHEMAS.containsKey(namespaceURI)) { + CustomLSInputImpl input = new CustomLSInputImpl(); + input.setPublicId(publicId); + String schema = SCHEMAS.get(namespaceURI); + input.setSystemId(requireNonNull(NullIdTest.class.getResource(schema)).toExternalForm()); + input.setBaseURI(baseURI); + InputStream stream = NullIdTest.class.getResourceAsStream(schema); + input.setCharacterStream(new InputStreamReader(requireNonNull(stream))); + return input; + } + } + if (systemId != null) { + CatalogFeatures features = CatalogFeatures.builder() + .with(CatalogFeatures.Feature.RESOLVE, "continue") + .build(); + CatalogResolver catalogResolver = catalogResolver(features); + return catalogResolver.resolveResource(type, namespaceURI, publicId, systemId, baseURI); + } + return null; + }; + } + + static class CustomLSInputImpl implements LSInput { + + private Reader characterStream; + private InputStream byteStream; + private String stringData; + private String systemId; + private String publicId; + private String baseURI; + private String encoding; + private boolean certifiedText; + + @Override + public Reader getCharacterStream() { + return characterStream; + } + + @Override + public void setCharacterStream(Reader characterStream) { + this.characterStream = characterStream; + } + + @Override + public InputStream getByteStream() { + return byteStream; + } + + @Override + public void setByteStream(InputStream byteStream) { + this.byteStream = byteStream; + } + + @Override + public String getStringData() { + return stringData; + } + + @Override + public void setStringData(String stringData) { + this.stringData = stringData; + } + + @Override + public String getSystemId() { + return systemId; + } + + @Override + public void setSystemId(String systemId) { + this.systemId = systemId; + } + + @Override + public String getPublicId() { + return publicId; + } + + @Override + public void setPublicId(String publicId) { + this.publicId = publicId; + } + + @Override + public String getBaseURI() { + return baseURI; + } + + @Override + public void setBaseURI(String baseURI) { + this.baseURI = baseURI; + } + + @Override + public String getEncoding() { + return encoding; + } + + @Override + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + @Override + public boolean getCertifiedText() { + return certifiedText; + } + + @Override + public void setCertifiedText(boolean certifiedText) { + this.certifiedText = certifiedText; + } + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd new file mode 100644 index 00000000000..41b0de3425b --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd new file mode 100644 index 00000000000..56d5a431211 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java new file mode 100644 index 00000000000..14215004937 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java @@ -0,0 +1,132 @@ +/* + * 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 common.dtd; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.xml.sax.XMLReader; + +/* + * @test + * @bug 8322214 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng common.dtd.DTDPropertiesTest + * @summary Verifies the getProperty function on DTD properties works the same + * as before the property 'jdk.xml.dtd.support' was introduced. + */ +public class DTDPropertiesTest { + // Xerces Property + public static final String DISALLOW_DTD = "http://apache.org/xml/features/disallow-doctype-decl"; + + /* + * DataProvider for verifying Xerces' disallow-DTD feature + * Fields: property name, setting (null indicates not specified), expected + */ + @DataProvider(name = "XercesProperty") + public Object[][] getXercesProperty() throws Exception { + return new Object[][] { + { DISALLOW_DTD, null, false}, + { DISALLOW_DTD, true, true}, + { DISALLOW_DTD, false, false}, + }; + } + + /* + * DataProvider for verifying StAX's supportDTD feature + * Fields: property name, setting (null indicates not specified), expected + */ + @DataProvider(name = "StAXProperty") + public Object[][] getStAXProperty() throws Exception { + return new Object[][] { + { XMLInputFactory.SUPPORT_DTD, null, true}, + { XMLInputFactory.SUPPORT_DTD, true, true}, + { XMLInputFactory.SUPPORT_DTD, false, false}, + }; + } + + /** + * Verifies the disallow DTD feature with SAX. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "XercesProperty") + public void testSAX(String name, Boolean setting, Boolean expected) throws Exception { + SAXParserFactory spf = SAXParserFactory.newDefaultInstance(); + if (setting != null) { + spf.setFeature(name, setting); + } + Assert.assertEquals((Boolean)spf.getFeature(name), expected); + System.out.println(spf.getFeature(name)); + + + SAXParser saxParser = spf.newSAXParser(); + XMLReader reader = saxParser.getXMLReader(); + Assert.assertEquals((Boolean)reader.getFeature(name), expected); + System.out.println(reader.getFeature(name)); + } + + /** + * Verifies the disallow DTD feature with DOM. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "XercesProperty") + public void testDOM(String name, Boolean setting, Boolean expected) throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + if (setting != null) { + dbf.setFeature(name, setting); + } + Assert.assertEquals((Boolean)dbf.getFeature(name), expected); + System.out.println(dbf.getFeature(name)); + } + + /** + * Verifies the StAX's supportDTD feature. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "StAXProperty") + public void testStAX(String name, Boolean setting, Boolean expected) throws Exception { + XMLInputFactory xif = XMLInputFactory.newInstance(); + if (setting != null) { + xif.setProperty(name, setting); + } + Assert.assertEquals((Boolean)xif.getProperty(name), expected); + System.out.println((Boolean)xif.getProperty(name)); + } +} diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java index 27b72b5cf7c..22c5c89b57b 100644 --- a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java +++ b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.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 @@ -26,7 +26,9 @@ * @bug 8297878 * @summary Key Encapsulation Mechanism API * @library /test/lib + * @build java.base/com.sun.crypto.provider.EvenKEMImpl * @modules java.base/com.sun.crypto.provider + * @run main/othervm Compliance */ import jdk.test.lib.Asserts; import jdk.test.lib.Utils; @@ -45,18 +47,19 @@ import com.sun.crypto.provider.DHKEM; +import static com.sun.crypto.provider.EvenKEMImpl.isEven; + public class Compliance { public static void main(String[] args) throws Exception { basic(); conform(); determined(); - try { - Security.insertProviderAt(new ProviderImpl(), 1); - delayed(); - } finally { - Security.removeProvider("XP"); - } + // Patch an alternate DHKEM in SunEC which is ahead of SunJCE + // in security provider listing. + Security.getProvider("SunEC") + .put("KEM.DHKEM", "com.sun.crypto.provider.EvenKEMImpl"); + delayed(); } // Encapsulated conformance checks @@ -220,34 +223,6 @@ static byte[] calcDetermined(long seed) throws Exception { return enc2; } - public static class ProviderImpl extends Provider { - ProviderImpl() { - super("XP", "1", "XP"); - put("KEM.DHKEM", "Compliance$KEMImpl"); - } - } - - static boolean isEven(Key k) { - return Arrays.hashCode(k.getEncoded()) % 2 == 0; - } - - public static class KEMImpl extends DHKEM { - - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewEncapsulator(pk, spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSpec spec) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewDecapsulator(sk, spec); - } - } - // Ensure delayed provider selection static void delayed() throws Exception { KeyPairGenerator g = KeyPairGenerator.getInstance("X25519"); @@ -266,7 +241,7 @@ static void delayed() throws Exception { KEM.Encapsulator eodd = kem.newEncapsulator(odd); KEM.Encapsulator eeven = kem.newEncapsulator(even); Asserts.assertEQ(eodd.providerName(), "SunJCE"); - Asserts.assertEQ(eeven.providerName(), "XP"); + Asserts.assertEQ(eeven.providerName(), "SunEC"); } static ECPublicKey badECKey() { diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java new file mode 100644 index 00000000000..dc478c25954 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java @@ -0,0 +1,51 @@ +/* + * 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 com.sun.crypto.provider; + +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; + +// The alternate DHKEM implementation used by the Compliance.java test. +public class EvenKEMImpl extends DHKEM { + + public static boolean isEven(Key k) { + return Arrays.hashCode(k.getEncoded()) % 2 == 0; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator( + PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewEncapsulator(pk, spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey sk, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewDecapsulator(sk, spec); + } +} diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java index f4048aaa68a..2aa398468cc 100644 --- a/test/jdk/java/foreign/TestLayouts.java +++ b/test/jdk/java/foreign/TestLayouts.java @@ -371,13 +371,13 @@ public void testVarHandleCaching() { } @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*Negative offset.*") + expectedExceptionsMessageRegExp=".*offset is negative.*") public void testScaleNegativeOffset() { JAVA_INT.scale(-1, 0); } @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*Negative index.*") + expectedExceptionsMessageRegExp=".*index is negative.*") public void testScaleNegativeIndex() { JAVA_INT.scale(0, -1); } diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java index d56f44388a4..b749c96ac54 100644 --- a/test/jdk/java/foreign/TestMemoryAccessInstance.java +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -164,6 +164,13 @@ public void badAccessOverflowInIndexedAccess(String t } } + @Test(dataProvider = "segmentAccessors") + public void negativeOffset(String testName, Accessor accessor) { + MemorySegment segment = MemorySegment.ofArray(new byte[100]); + assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, -ValueLayout.JAVA_LONG.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> accessor.set(segment, -ValueLayout.JAVA_LONG.byteSize(), accessor.value)); + } + static final ByteOrder NE = ByteOrder.nativeOrder(); @DataProvider(name = "segmentAccessors") diff --git a/test/jdk/java/foreign/TestScope.java b/test/jdk/java/foreign/TestScope.java index 337dce7d0ca..b7bcc4d373c 100644 --- a/test/jdk/java/foreign/TestScope.java +++ b/test/jdk/java/foreign/TestScope.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 @@ -31,8 +31,11 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.HexFormat; +import java.util.stream.LongStream; import static org.testng.Assert.*; @@ -108,6 +111,30 @@ public void testSameLookupScope() { testDerivedBufferScope(segment1.reinterpret(10)); } + @Test + public void testZeroedOfAuto() { + testZeroed(Arena.ofAuto()); + } + + @Test + public void testZeroedGlobal() { + testZeroed(Arena.global()); + } + + @Test + public void testZeroedOfConfined() { + try (Arena arena = Arena.ofConfined()) { + testZeroed(arena); + } + } + + @Test + public void testZeroedOfShared() { + try (Arena arena = Arena.ofShared()) { + testZeroed(arena); + } + } + void testDerivedBufferScope(MemorySegment segment) { ByteBuffer buffer = segment.asByteBuffer(); MemorySegment.Scope expectedScope = segment.scope(); @@ -119,4 +146,14 @@ void testDerivedBufferScope(MemorySegment segment) { IntBuffer view = buffer.asIntBuffer(); assertEquals(expectedScope, MemorySegment.ofBuffer(view).scope()); } + + private static final MemorySegment ZEROED_MEMORY = MemorySegment.ofArray(new byte[8102]); + + void testZeroed(Arena arena) { + long byteSize = ZEROED_MEMORY.byteSize(); + var segment = arena.allocate(byteSize, Long.BYTES); + long mismatch = ZEROED_MEMORY.mismatch(segment); + assertEquals(mismatch, -1); + } + } diff --git a/test/jdk/java/foreign/TestScopedOperations.java b/test/jdk/java/foreign/TestScopedOperations.java index 70223c00c00..d680d234145 100644 --- a/test/jdk/java/foreign/TestScopedOperations.java +++ b/test/jdk/java/foreign/TestScopedOperations.java @@ -27,6 +27,7 @@ */ import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -135,6 +136,8 @@ public void testOpOutsideConfinement(String name, ScopedOperation scopedO ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_FLOAT, new float[]{0}), "Arena::allocateFrom/float"); ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_LONG, new long[]{0}), "Arena::allocateFrom/long"); ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_DOUBLE, new double[]{0}), "Arena::allocateFrom/double"); + var source = MemorySegment.ofArray(new byte[]{}); + ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_INT, source, JAVA_BYTE, 0, 1), "Arena::allocateFrom/5arg"); }; @DataProvider(name = "scopedOperations") diff --git a/test/jdk/java/foreign/TestSegmentAllocators.java b/test/jdk/java/foreign/TestSegmentAllocators.java index 0e0c49320da..87418f39d90 100644 --- a/test/jdk/java/foreign/TestSegmentAllocators.java +++ b/test/jdk/java/foreign/TestSegmentAllocators.java @@ -44,6 +44,8 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.function.Function; @@ -189,6 +191,81 @@ public void testAllocatorAllocateFromHeapSegment() { } } + // Invariant checking tests for the SegmentAllocator method: + // MemorySegment allocateFrom(ValueLayout elementLayout, + // MemorySegment source, + // ValueLayout sourceElementLayout, + // long sourceOffset, + // long elementCount) { + @Test + public void testAllocatorAllocateFromArguments() { + try (Arena arena = Arena.ofConfined()) { + var sourceElements = 2; + var source = arena.allocate(ValueLayout.JAVA_LONG, sourceElements); + var elementLayout = ValueLayout.JAVA_INT; + var sourceElementLayout = ValueLayout.JAVA_INT; + + // IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, ValueLayout.JAVA_BYTE, 0, 1) + ); + + // IllegalArgumentException if source segment/offset + // are incompatible with the alignment constraint + // in the source element layout + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source.asSlice(1), sourceElementLayout, 0, 1) + ); + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 1, 1) + ); + + // IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout.withByteAlignment(elementLayout.byteAlignment() * 2), source, sourceElementLayout, 1, 1) + ); + + // IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated + // with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} + // This is tested in TestScopedOperations + + // WrongThreadException if this method is called from a thread {@code T}, + // such that {@code source.isAccessibleBy(T) == false} + CompletableFuture future = CompletableFuture.supplyAsync(Arena::ofConfined); + try { + Arena otherThreadArena = future.get(); + assertThrows(WrongThreadException.class, () -> + otherThreadArena.allocateFrom(elementLayout, source, sourceElementLayout, 0, 1) + ); + } catch (ExecutionException | InterruptedException e) { + fail("Unable to create arena", e); + } + + // IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, Long.MAX_VALUE) + ); + + // IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())} + assertThrows(IndexOutOfBoundsException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, source.byteSize() - (1 * sourceElementLayout.byteAlignment()) + elementLayout.byteSize(), 1) + ); + + // IndexOutOfBoundsException if {@code sourceOffset < 0} + assertThrows(IndexOutOfBoundsException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, -elementLayout.byteSize(), 1) + ); + + // IllegalArgumentException if {@code elementCount < 0} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, -1) + ); + + + } + } + + @Test public void testArrayAllocateDelegation() { AtomicInteger calls = new AtomicInteger(); diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java index 414cd0a8451..88636bf5420 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -145,6 +145,66 @@ public void testHyperAlignedDst() { MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4); } + @Test + public void testCopy5ArgWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, -1, dst, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, 0, -1) + ); + } + + @Test + public void testCopy7ArgWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, -1, dst, JAVA_BYTE, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, 0, -1) + ); + } + + @Test + public void testCopyFromArrayWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + byte[] dst = new byte[] {1, 2, 3, 4}; + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, -1, dst, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, 0, -1) + ); + } + + @Test + public void testCopyToArrayWithNegativeValues() { + byte[] src = new byte[] {1, 2, 3, 4}; + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, -1, dst, JAVA_BYTE, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, JAVA_BYTE, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, JAVA_BYTE, 0, -1) + ); + } + enum Type { // Byte BYTE(byte.class, JAVA_BYTE, i -> (byte)i), diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 94b49eb7e59..44ecd12ba5e 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -43,6 +43,7 @@ import java.util.function.Supplier; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; import static org.testng.Assert.*; public class TestSegments { @@ -55,14 +56,13 @@ public void testBadAllocateAlign(long size, long align) { @Test public void testZeroLengthNativeSegment() { try (Arena arena = Arena.ofConfined()) { - Arena session = arena; - var segment = session.allocate(0, 1); + var segment = arena.allocate(0, 1); assertEquals(segment.byteSize(), 0); MemoryLayout seq = MemoryLayout.sequenceLayout(0, JAVA_INT); - segment = session.allocate(seq); + segment = arena.allocate(seq); assertEquals(segment.byteSize(), 0); assertEquals(segment.address() % seq.byteAlignment(), 0); - segment = session.allocate(0, 4); + segment = arena.allocate(0, 4); assertEquals(segment.byteSize(), 0); assertEquals(segment.address() % 4, 0); MemorySegment rawAddress = MemorySegment.ofAddress(segment.address()); @@ -133,8 +133,7 @@ public void testDerivedScopes(Supplier segmentSupplier) { @Test public void testEqualsOffHeap() { try (Arena arena = Arena.ofConfined()) { - Arena scope1 = arena; - MemorySegment segment = scope1.allocate(100, 1); + MemorySegment segment = arena.allocate(100, 1); assertEquals(segment, segment.asReadOnly()); assertEquals(segment, segment.asSlice(0, 100)); assertNotEquals(segment, segment.asSlice(10, 90)); diff --git a/test/jdk/java/foreign/UpcallTestHelper.java b/test/jdk/java/foreign/UpcallTestHelper.java index bbc01959ccd..8adf5580f51 100644 --- a/test/jdk/java/foreign/UpcallTestHelper.java +++ b/test/jdk/java/foreign/UpcallTestHelper.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 @@ -29,8 +29,9 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; public class UpcallTestHelper extends NativeTestHelper { @@ -50,16 +51,18 @@ public OutputAnalyzer runInNewProcess(Class target, boolean useSpec, List invokePark()); + assertContains(output, "reason:NATIVE"); assertContains(output, "(Native Method)"); - assertDoesNotContain(output, "<== monitors"); + } + + /** + * Test parking in class initializer. + */ + @Test + void testPinnedCausedByClassInitializer() throws Exception { + class C { + static { + park(); + } + } + String output = run(C::new); + assertContains(output, "reason:NATIVE"); + assertContains(output, ""); + } + + /** + * Test contention writing to System.out when pinned. The test creates four threads + * that write to System.out when pinned, this is enough to potentially deadlock + * without the changes in JDK-8322846. + */ + @Test + void testContention() throws Exception { + // use several classes to avoid duplicate stack traces + class C1 { + synchronized void print() { + System.out.println("hello"); + } + } + class C2 { + synchronized void print() { + System.out.println("hello"); + } + } + class C3 { + synchronized void print() { + System.out.println("hello"); + } + } + class C4 { + synchronized void print() { + System.out.println("hello"); + } + } + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + executor.submit(() -> { + new C1().print(); + }); + executor.submit(() -> { + new C2().print(); + }); + executor.submit(() -> { + new C3().print(); + }); + executor.submit(() -> { + new C4().print(); + }); + } } /** diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java new file mode 100644 index 00000000000..e00cf89fb8c --- /dev/null +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java @@ -0,0 +1,123 @@ +/* + * 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 + * 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 8322818 + * @summary Stress test Thread.getStackTrace on a virtual thread that is pinned + * @requires vm.debug != true + * @modules java.base/java.lang:+open + * @library /test/lib + * @run main/othervm GetStackTraceALotWhenPinned 500000 + */ + +/* + * @test + * @requires vm.debug == true + * @modules java.base/java.lang:+open + * @library /test/lib + * @run main/othervm/timeout=300 GetStackTraceALotWhenPinned 200000 + */ + +import java.time.Instant; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; +import jdk.test.lib.thread.VThreadRunner; + +public class GetStackTraceALotWhenPinned { + + public static void main(String[] args) throws Exception { + // need at least two carrier threads when main thread is a virtual thread + if (Thread.currentThread().isVirtual()) { + VThreadRunner.ensureParallelism(2); + } + + int iterations = Integer.parseInt(args[0]); + var barrier = new Barrier(2); + + // Start a virtual thread that loops doing Thread.yield and parking while pinned. + // This loop creates the conditions for the main thread to sample the stack trace + // as it transitions from being unmounted to parking while pinned. + var thread = Thread.startVirtualThread(() -> { + boolean timed = false; + for (int i = 0; i < iterations; i++) { + // wait for main thread to arrive + barrier.await(); + + Thread.yield(); + synchronized (GetStackTraceALotWhenPinned.class) { + if (timed) { + LockSupport.parkNanos(Long.MAX_VALUE); + } else { + LockSupport.park(); + } + } + timed = !timed; + } + }); + + long lastTimestamp = System.currentTimeMillis(); + for (int i = 0; i < iterations; i++) { + // wait for virtual thread to arrive + barrier.await(); + + thread.getStackTrace(); + LockSupport.unpark(thread); + + long currentTime = System.currentTimeMillis(); + if ((currentTime - lastTimestamp) > 500) { + System.out.format("%s %d remaining ...%n", Instant.now(), (iterations - i)); + lastTimestamp = currentTime; + } + } + } + + /** + * Alow threads wait for each other to reach a common barrier point. This class does + * not park threads that are waiting for the barrier to trip, instead it spins. This + * makes it suitable for tests that use LockSupport.park or Thread.yield. + */ + private static class Barrier { + private final int parties; + private final AtomicInteger count; + private volatile int generation; + + Barrier(int parties) { + this.parties = parties; + this.count = new AtomicInteger(parties); + } + + void await() { + int g = generation; + if (count.decrementAndGet() == 0) { + count.set(parties); + generation = g + 1; + } else { + while (generation == g) { + Thread.onSpinWait(); + } + } + } + + } +} diff --git a/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java b/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java index 7d369d7ddd9..794ede84a92 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java +++ b/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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,7 @@ * @test * @bug 8236246 * @modules java.base/sun.nio.ch - * @run testng InterruptibleOrNot + * @run junit InterruptibleOrNot * @summary Test SelectorProviderImpl.openDatagramChannel(boolean) to create * DatagramChannel objects that optionally support interrupt */ @@ -40,152 +40,178 @@ import java.nio.channels.ClosedByInterruptException; import java.nio.channels.DatagramChannel; import java.time.Duration; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.Arrays; import sun.nio.ch.DefaultSelectorProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.function.Executable; +import static org.junit.jupiter.api.Assertions.*; -@Test public class InterruptibleOrNot { + // DatagramChannel implementation class + private static String dcImplClassName; - public void testInterruptBeforeInterruptibleReceive() throws Exception { - testInterruptBeforeReceive(true); - } - - public void testInterruptDuringInterruptibleReceive() throws Exception { - testInterruptDuringReceive(true); - } - - public void testInterruptBeforeUninterruptibleReceive() throws Exception { - testInterruptBeforeReceive(false); - } - - public void testInterruptDuringUninterruptibleReceive() throws Exception { - testInterruptDuringReceive(false); - } - - public void testInterruptBeforeInterruptibleSend() throws Exception { - testInterruptBeforeSend(true); + @BeforeAll + static void setup() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + dcImplClassName = dc.getClass().getName(); + } } - public void testInterruptBeforeUninterruptibleSend() throws Exception { - testInterruptBeforeSend(false); + /** + * Call DatagramChannel.receive with the interrupt status set, the DatagramChannel + * is interruptible. + */ + @Test + public void testInterruptBeforeInterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + Thread.currentThread().interrupt(); + assertThrows(ClosedByInterruptException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt status + } } /** - * Test invoking DatagramChannel receive with interrupt status set + * Test interrupting a thread blocked in DatagramChannel.receive, the DatagramChannel + * is interruptible. */ - static void testInterruptBeforeReceive(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timeout = scheduleClose(dc, Duration.ofSeconds(2)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - Thread.currentThread().interrupt(); - assertThrows(expectedException(interruptible), () -> dc.receive(buf)); - } finally { - timeout.cancel(false); - } + @Test + public void testInterruptDuringInterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + Thread thread = Thread.currentThread(); + onReceive(thread::interrupt); + assertThrows(ClosedByInterruptException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Test Thread.interrupt when target thread is blocked in DatagramChannel receive + * Call DatagramChannel.receive with the interrupt status set, the DatagramChannel + * is not interruptible. */ - static void testInterruptDuringReceive(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timerTask = scheduleClose(dc, Duration.ofSeconds(5)); - Future interruptTask = scheduleInterrupt(Thread.currentThread(), Duration.ofSeconds(1)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - assertThrows(expectedException(interruptible), () -> dc.receive(buf)); - } finally { - timerTask.cancel(false); - interruptTask.cancel(false); - } + @Test + public void testInterruptBeforeUninterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(false)) { + ByteBuffer buf = ByteBuffer.allocate(100); + onReceive(() -> { + // close the channel after a delay to ensure receive wakes up + Thread.sleep(1000); + dc.close(); + }); + Thread.currentThread().interrupt(); + assertThrows(AsynchronousCloseException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Test invoking DatagramChannel send with interrupt status set + * Test interrupting a thread blocked in DatagramChannel.receive, the DatagramChannel + * is not interruptible. */ - static void testInterruptBeforeSend(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timeout = scheduleClose(dc, Duration.ofSeconds(2)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - SocketAddress target = dc.getLocalAddress(); - Thread.currentThread().interrupt(); - if (interruptible) { - assertThrows(ClosedByInterruptException.class, () -> dc.send(buf, target)); - } else { - int n = dc.send(buf, target); - assertTrue(n == 100); - } - } finally { - timeout.cancel(false); - } + @Test + public void testInterruptDuringUninterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + + Thread thread = Thread.currentThread(); + onReceive(() -> { + // interrupt should not cause the receive to wakeup + thread.interrupt(); + + // close the channel after a delay to ensure receive wakes up + Thread.sleep(1000); + dc.close(); + }); + assertThrows(AsynchronousCloseException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Creates a DatagramChannel that is interruptible or not. + * Call DatagramChannel.send with the interrupt status set, the DatagramChannel + * is interruptible. */ - static DatagramChannel openDatagramChannel(boolean interruptible) throws IOException { - if (interruptible) { - return DatagramChannel.open(); - } else { - return DefaultSelectorProvider.get().openUninterruptibleDatagramChannel(); + @Test + public void testInterruptBeforeInterruptibleSend() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + SocketAddress target = dc.getLocalAddress(); + Thread.currentThread().interrupt(); + assertThrows(ClosedByInterruptException.class, () -> dc.send(buf, target)); + assertFalse(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt } } /** - * Expect ClosedByInterruptException if interruptible. + * Call DatagramChannel.send with the interrupt status set, the DatagramChannel + * is not interruptible. */ - static Class expectedException(boolean expectInterrupt) { - if (expectInterrupt) { - return ClosedByInterruptException.class; - } else { - return AsynchronousCloseException.class; + @Test + public void testInterruptBeforeUninterruptibleSend() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(false)) { + ByteBuffer buf = ByteBuffer.allocate(100); + SocketAddress target = dc.getLocalAddress(); + Thread.currentThread().interrupt(); + int n = dc.send(buf, target); + assertEquals(100, n); + assertTrue(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt status } } /** - * Schedule the given object to be closed. + * Creates a DatagramChannel that is interruptible or not, and bound to the loopback + * address. */ - static Future scheduleClose(Closeable c, Duration timeout) { - long nanos = TimeUnit.NANOSECONDS.convert(timeout); - return STPE.schedule(() -> { - c.close(); - return null; - }, nanos, TimeUnit.NANOSECONDS); + static DatagramChannel boundDatagramChannel(boolean interruptible) throws IOException { + DatagramChannel dc; + if (interruptible) { + dc = DatagramChannel.open(); + } else { + dc = DefaultSelectorProvider.get().openUninterruptibleDatagramChannel(); + } + try { + dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + } catch (IOException ioe) { + dc.close(); + throw ioe; + } + return dc; } /** - * Schedule the given thread to be interrupted. + * Runs the given action when the current thread is sampled in DatagramChannel.receive. */ - static Future scheduleInterrupt(Thread t, Duration timeout) { - long nanos = TimeUnit.NANOSECONDS.convert(timeout); - return STPE.schedule(t::interrupt, nanos, TimeUnit.NANOSECONDS); + static void onReceive(Executable action) { + Thread target = Thread.currentThread(); + Thread.ofPlatform().daemon().start(() -> { + try { + boolean found = false; + while (!found) { + Thread.sleep(20); + StackTraceElement[] stack = target.getStackTrace(); + found = Arrays.stream(stack) + .anyMatch(e -> dcImplClassName.equals(e.getClassName()) + && "receive".equals(e.getMethodName())); + } + action.execute(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + }); } - - static final ScheduledExecutorService STPE = Executors.newScheduledThreadPool(0); } diff --git a/test/jdk/java/time/test/java/time/format/TestUTCParse.java b/test/jdk/java/time/test/java/time/format/TestUTCParse.java index 6da94f04f04..c1766b47030 100644 --- a/test/jdk/java/time/test/java/time/format/TestUTCParse.java +++ b/test/jdk/java/time/test/java/time/format/TestUTCParse.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 @@ -23,7 +23,7 @@ /* * @test * @modules jdk.localedata - * @bug 8303440 8317979 + * @bug 8303440 8317979 8322647 * @summary Test parsing "UTC-XX:XX" text works correctly */ package test.java.time.format; @@ -43,8 +43,8 @@ public class TestUTCParse { static { - // Assuming CLDR's SHORT name for "America/Juneau" - // produces "UTC\u212209:00" + // Assuming CLDR's SHORT name for "America/Manaus" + // produces "UTC\u221204:00" System.setProperty("java.locale.providers", "CLDR"); } @@ -60,9 +60,9 @@ public Object[][] utcZoneIdStrings() { @Test public void testUTCShortNameRoundTrip() { var fmt = DateTimeFormatter.ofPattern("z", Locale.FRANCE); - var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Juneau")); + var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Manaus")); var formatted = fmt.format(zdt); - assertEquals(formatted, "UTC\u221209:00"); + assertEquals(formatted, "UTC\u221204:00"); assertEquals(fmt.parse(formatted).query(TemporalQueries.zoneId()), zdt.getZone()); } diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index c4fdc5ca2e0..53788c899b3 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -25,7 +25,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 8274658 8283277 8296239 + * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -86,7 +86,7 @@ public class ValidateISO4217 { // Codes that are obsolete, do not have related country, extra currency private static final String otherCodes = "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" - + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-HRK-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" + "YUM-ZMK-ZWD-ZWN-ZWR"; @@ -168,7 +168,7 @@ private static void processColumns(StringTokenizer tokens, String country) throw if (format == null) { createDateFormat(); } - // If the cut-over already passed, test the changed data too + // If the cut-over already passed, use the new curency for ISO4217Codes if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) { currency = tokens.nextToken(); numeric = tokens.nextToken(); @@ -267,20 +267,21 @@ private static List additionalCodesProvider() { * throws an IllegalArgumentException or returns null. The test data * supplied is every possible combination of AA -> ZZ. */ - @ParameterizedTest - @MethodSource("codeCombos") - public void twoLetterCodesTest(String country) { - if (codes[toIndex(country)] == UNDEFINED) { - // if a code is undefined / 0, creating a Currency from it - // should throw an IllegalArgumentException - assertThrows(IllegalArgumentException.class, - ()-> Currency.getInstance(Locale.of("", country)), - "Error: This should be an undefined code and throw IllegalArgumentException: " + country); - } else if (codes[toIndex(country)] == SKIPPED) { - // if a code is marked as skipped / 2, creating a Currency from it - // should return null - assertNull(Currency.getInstance(Locale.of("", country)), - "Error: Currency.getInstance() for this locale should return null: " + country); + @Test + public void twoLetterCodesTest() { + for (String country : codeCombos()) { + if (codes[toIndex(country)] == UNDEFINED) { + // if a code is undefined / 0, creating a Currency from it + // should throw an IllegalArgumentException + assertThrows(IllegalArgumentException.class, + () -> Currency.getInstance(Locale.of("", country)), + "Error: This should be an undefined code and throw IllegalArgumentException: " + country); + } else if (codes[toIndex(country)] == SKIPPED) { + // if a code is marked as skipped / 2, creating a Currency from it + // should return null + assertNull(Currency.getInstance(Locale.of("", country)), + "Error: Currency.getInstance() for this locale should return null: " + country); + } } } diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/tablea1.txt index 4e33a62c05e..6e85de5e6d2 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/tablea1.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 175 -# (As of 31 March 2023) +# Amendments up until ISO 4217 AMENDMENT NUMBER 176 +# (As of 06 December 2023) # # Version FILEVERSION=3 -DATAVERSION=175 +DATAVERSION=176 # ISO 4217 currency data AF AFN 971 2 @@ -67,9 +67,9 @@ CD CDF 976 2 CK NZD 554 2 CR CRC 188 2 CI XOF 952 0 -HR HRK 191 2 2022-12-31-23-00-00 EUR 978 2 +HR EUR 978 2 CU CUP 192 2 -CW ANG 532 2 +CW ANG 532 2 2025-04-01-04-00-00 XCG 532 2 CY EUR 978 2 CZ CZK 203 2 DK DKK 208 2 @@ -233,7 +233,7 @@ LK LKR 144 2 SD SDG 938 2 SR SRD 968 2 SJ NOK 578 2 -SX ANG 532 2 +SX ANG 532 2 2025-04-01-04-00-00 XCG 532 2 SZ SZL 748 2 SE SEK 752 2 CH CHF 756 2 diff --git a/test/jdk/java/util/Locale/LocaleProviders.java b/test/jdk/java/util/Locale/LocaleProviders.java index c4acb0689b1..556409fb650 100644 --- a/test/jdk/java/util/Locale/LocaleProviders.java +++ b/test/jdk/java/util/Locale/LocaleProviders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, 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 @@ -35,6 +35,10 @@ import java.util.logging.StreamHandler; import java.util.spi.*; import java.util.stream.IntStream; +import java.util.stream.Stream; + +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; import sun.util.locale.provider.LocaleProviderAdapter; import static java.util.logging.LogManager.*; @@ -447,7 +451,8 @@ static void bug8248695Test() { } } - // Run only if the platform locale is en-GB + // Run only if the underlying platform locale is en-GB + // (Setting the java locale via command line properties does not substitute this) static void bug8257964Test() { var defLoc = Locale.getDefault(Locale.Category.FORMAT); var type = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, Locale.UK) @@ -476,4 +481,30 @@ static void bug8257964Test() { "provider is not HOST: " + type); } } + + /* Method is used by the LocaleProviders* related tests to launch a + * LocaleProviders test method with the appropriate LocaleProvider (e.g. CLDR, + * COMPAT, ETC.) + */ + static void test(String prefList, String methodName, String... params) throws Throwable { + + List command = List.of( + "-ea", "-esa", + "-cp", Utils.TEST_CLASS_PATH, + // Required for LocaleProvidersLogger + "-Djava.util.logging.config.class=LocaleProviders$LogConfig", + "-Djava.locale.providers=" + prefList, + "--add-exports=java.base/sun.util.locale.provider=ALL-UNNAMED", + "LocaleProviders", methodName); + + // Build process with arguments, if required by the method + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Stream.concat(command.stream(), Stream.of(params)).toList()); + + // Evaluate process status + int exitCode = ProcessTools.executeCommand(pb).getExitValue(); + if (exitCode != 0) { + throw new RuntimeException("Unexpected exit code: " + exitCode); + } + } } diff --git a/test/jdk/java/util/Locale/LocaleProvidersCalendar.java b/test/jdk/java/util/Locale/LocaleProvidersCalendar.java new file mode 100644 index 00000000000..93d11da772b --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersCalendar.java @@ -0,0 +1,74 @@ +/* + * 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 + * 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 8228465 8232871 8257964 + * @summary Test any Calendar Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersCalendar + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; + +import static org.junit.jupiter.api.condition.OS.MAC; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +public class LocaleProvidersCalendar { + + /* + * 8228465 (Windows only): Ensure correct ERA display name under HOST Windows + */ + @Test + @EnabledOnOs(WINDOWS) + public void gregCalEraHost() throws Throwable { + LocaleProviders.test("HOST", "bug8228465Test"); + } + + /* + * 8232871 (macOS only): Ensure correct Japanese calendar values under + * HOST Mac. + */ + @Test + @EnabledOnOs(MAC) + public void japaneseCalValuesHost() throws Throwable { + LocaleProviders.test("HOST", "bug8232871Test"); + } + + /* + * 8257964 (macOS/Windows only): Ensure correct Calendar::getMinimalDaysInFirstWeek + * value under HOST Windows / Mac. Only run against machine with underlying + * OS locale of en-GB. + */ + @Test + @EnabledOnOs({WINDOWS, MAC}) + @EnabledIfSystemProperty(named = "user.language", matches = "en") + @EnabledIfSystemProperty(named = "user.country", matches = "GB") + public void minDaysFirstWeekHost() throws Throwable { + LocaleProviders.test("HOST", "bug8257964Test"); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java new file mode 100644 index 00000000000..e304dc73fac --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java @@ -0,0 +1,46 @@ +/* + * 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 + * 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 8248695 + * @summary Test any java.time.DateTimeFormatter Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersDateTimeFormatter + */ + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersDateTimeFormatter { + + /* + * 8248695: Ensure DateTimeFormatter::ofLocalizedDate does not throw exception + * under HOST (date only pattern leaks time field) + */ + @Test + public void dateOnlyJavaTimePattern() throws Throwable { + LocaleProviders.test("HOST", "bug8248695Test"); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersFormat.java b/test/jdk/java/util/Locale/LocaleProvidersFormat.java new file mode 100644 index 00000000000..0584b82b318 --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersFormat.java @@ -0,0 +1,110 @@ +/* + * 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 + * 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 7198834 8001440 8013086 8013903 8027289 8232860 + * @summary Test any java.text.Format Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * providersrc.spi.src.tznp + * providersrc.spi.src.tznp8013086 + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersFormat + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledOnOs; + +import static org.junit.jupiter.api.condition.OS.MAC; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +public class LocaleProvidersFormat { + + /* + * 7198834: Ensure under Windows/HOST, adapter does not append an extra space for date patterns. + */ + @Test + @EnabledOnOs(WINDOWS) + public void dateFormatExtraSpace() throws Throwable { + LocaleProviders.test("HOST", "bug7198834Test"); + } + + /* + * 8001440: Ensure under CLDR, when number extension of the language + * tag is invalid, test program does not throw exception when calling + * NumberFormat::format. + */ + @Test + public void formatWithInvalidLocaleExtension() throws Throwable { + LocaleProviders.test("CLDR", "bug8001440Test"); + } + + /* + * 8013086: Ensure a custom TimeZoneNameProvider does not cause an NPE + * in simpleDateFormat, as SimpleDateFormat::matchZoneString expects the + * name array is fully filled with non-null names. + */ + @Test + public void simpleDateFormatWithTZNProvider() throws Throwable { + LocaleProviders.test("JRE,SPI", "bug8013086Test", "ja", "JP"); + LocaleProviders.test("COMPAT,SPI", "bug8013086Test", "ja", "JP"); + } + + /* + * 8013903 (Windows only): Ensure HOST adapter with Japanese locale produces + * the correct Japanese era, month, day names. + */ + @Test + @EnabledOnOs(WINDOWS) + public void windowsJapaneseDateFields() throws Throwable { + LocaleProviders.test("HOST,JRE", "bug8013903Test"); + LocaleProviders.test("HOST", "bug8013903Test"); + LocaleProviders.test("HOST,COMPAT", "bug8013903Test"); + } + + /* + * 8027289: Ensure if underlying system format locale is zh_CN, the Window's currency + * symbol under HOST provider is \u00A5, the yen (yuan) sign. + */ + @Test + @EnabledOnOs(WINDOWS) + @EnabledIfSystemProperty(named = "user.language", matches = "zh") + @EnabledIfSystemProperty(named = "user.country", matches = "CN") + public void windowsChineseCurrencySymbol() throws Throwable { + LocaleProviders.test("JRE,HOST", "bug8027289Test", "FFE5"); + LocaleProviders.test("COMPAT,HOST", "bug8027289Test", "FFE5"); + LocaleProviders.test("HOST", "bug8027289Test", "00A5"); + } + + /* + * 8232860 (macOS/Windows only): Ensure the Host adapter returns the number + * pattern for number/integer instances, which require optional fraction digits. + */ + @Test + @EnabledOnOs({WINDOWS, MAC}) + public void hostOptionalFracDigits() throws Throwable { + LocaleProviders.test("HOST", "bug8232860Test"); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersLogger.java b/test/jdk/java/util/Locale/LocaleProvidersLogger.java new file mode 100644 index 00000000000..a6e15914c3b --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersLogger.java @@ -0,0 +1,49 @@ +/* + * 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 + * 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 8245241 8246721 8261919 + * @summary Test the Locale provider preference is logged + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm -Djdk.lang.Process.allowAmbiguousCommands=false LocaleProvidersLogger + */ + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersLogger { + + /* + * 8245241 8246721 8261919: Ensure if an incorrect system property for locale providers is set, + * it should be logged and presented to the user. The option + * jdk.lang.Process.allowAmbiguousCommands=false is needed for properly escaping + * double quotes in the string argument. + */ + @Test + public void logIncorrectLocaleProvider() throws Throwable { + LocaleProviders.test("FOO", "bug8245241Test", + "Invalid locale provider adapter \"FOO\" ignored."); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersRun.java b/test/jdk/java/util/Locale/LocaleProvidersRun.java index 947633a8e21..7b6e87247a0 100644 --- a/test/jdk/java/util/Locale/LocaleProvidersRun.java +++ b/test/jdk/java/util/Locale/LocaleProvidersRun.java @@ -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 @@ -23,175 +23,151 @@ /* * @test - * @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577 - * 8010666 8013086 8013233 8013903 8015960 8028771 8054482 8062006 - * 8150432 8215913 8220227 8228465 8232871 8232860 8236495 8245241 - * 8246721 8248695 8257964 8261919 - * @summary tests for "java.locale.providers" system property - * @requires vm.flagless + * @bug 6336885 7196799 7197573 8008577 8010666 8013233 8015960 8028771 + * 8054482 8062006 8150432 8215913 8220227 8236495 + * @summary General Locale provider test (ex: adapter loading). See the + * other LocaleProviders* test classes for more specific tests (ex: + * java.text.Format related bugs). * @library /test/lib * @build LocaleProviders - * providersrc.spi.src.tznp - * providersrc.spi.src.tznp8013086 - * @modules java.base/sun.util.locale - * java.base/sun.util.locale.provider - * @run main/othervm -Djdk.lang.Process.allowAmbiguousCommands=false LocaleProvidersRun + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersRun */ import java.util.Locale; +import java.util.stream.Stream; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +/* + * Note: If this test launches too many JVMs, consider increasing timeout. + * As the LocaleProvider is set during java startup time, this test and the subclasses + * will always have to launch a separate JVM for testing of different providers. + */ public class LocaleProvidersRun { - public static void main(String[] args) throws Throwable { - //get the platform default locales - Locale platDefLoc = Locale.getDefault(Locale.Category.DISPLAY); - String defLang = platDefLoc.getLanguage(); - String defCtry = platDefLoc.getCountry(); - System.out.println("DEFLANG = " + defLang); - System.out.println("DEFCTRY = " + defCtry); + private static String defLang; + private static String defCtry; + private static String defFmtLang; + private static String defFmtCtry; + + // Get the system default locale values. Used to decide param values for tests. + @BeforeAll + static void setUp() { + Locale platDefLoc = Locale.getDefault(Locale.Category.DISPLAY); Locale platDefFormat = Locale.getDefault(Locale.Category.FORMAT); - String defFmtLang = platDefFormat.getLanguage(); - String defFmtCtry = platDefFormat.getCountry(); - System.out.println("DEFFMTLANG = " + defFmtLang); - System.out.println("DEFFMTCTRY = " + defFmtCtry); - - //Run Test - //testing HOST is selected for the default locale, - // if specified on Windows or MacOSX + defLang = platDefLoc.getLanguage(); + defCtry = platDefLoc.getCountry(); + defFmtLang = platDefFormat.getLanguage(); + defFmtCtry = platDefFormat.getCountry(); + + // Print out system defaults for diagnostic purposes + System.out.printf("DEFLANG = %s, DEFCTRY = %s, DEFFMTLANG = %s, DEFFMTCTRY = %s", + defLang, defCtry, defFmtLang, defFmtCtry); + } + + /* + * Test the adapter loading logic in LocaleProviderAdapter. + * Ensures that correct fallbacks are implemented. + */ + @ParameterizedTest + @MethodSource + public void adapterTest(String prefList, String param1, + String param2, String param3) throws Throwable { + LocaleProviders.test(prefList, "adapterTest", param1, param2, param3); + } + + /* + * Data provider which only launches against the LocaleProvider::adapterTest + * method. The arguments are dictated based off the operating system/platform + * Locale. Tests against variety of provider orders. + */ + private static Stream adapterTest() { + // Testing HOST is selected for the default locale if specified on Windows or MacOSX String osName = System.getProperty("os.name"); String param1 = "JRE"; - if(osName.startsWith("Windows") || osName.startsWith("Mac")) { + if (osName.startsWith("Windows") || osName.startsWith("Mac")) { param1 = "HOST"; } - testRun("HOST,JRE", "adapterTest", param1, defLang, defCtry); - //testing HOST is NOT selected for the non-default locale, if specified - //Try to find the locale JRE supports which is not the platform default + // Testing HOST is NOT selected for the non-default locale, if specified + // try to find the locale JRE supports which is not the platform default // (HOST supports that one) String param2; String param3; - if (!defLang.equals("en") && !defFmtLang.equals("en")){ + if (!defLang.equals("en") && !defFmtLang.equals("en")) { param2 = "en"; param3 = "US"; - } else if(!defLang.equals("ja") && !defFmtLang.equals("ja")){ + } else if (!defLang.equals("ja") && !defFmtLang.equals("ja")) { param2 = "ja"; param3 = "JP"; } else { param2 = "zh"; param3 = "CN"; } - testRun("HOST,JRE", "adapterTest", "JRE", param2, param3); - - //testing SPI is NOT selected, as there is none. - testRun("SPI,JRE", "adapterTest", "JRE", "en", "US"); - testRun("SPI,COMPAT", "adapterTest", "JRE", "en", "US"); - - //testing the order, variant #1. This assumes en_GB DateFormat data are - // available both in JRE & CLDR - testRun("CLDR,JRE", "adapterTest", "CLDR", "en", "GB"); - testRun("CLDR,COMPAT", "adapterTest", "CLDR", "en", "GB"); - - //testing the order, variant #2. This assumes en_GB DateFormat data are - // available both in JRE & CLDR - testRun("JRE,CLDR", "adapterTest", "JRE", "en", "GB"); - testRun("COMPAT,CLDR", "adapterTest", "JRE", "en", "GB"); - - //testing the order, variant #3 for non-existent locale in JRE - // assuming "haw" is not in JRE. - testRun("JRE,CLDR", "adapterTest", "CLDR", "haw", ""); - testRun("COMPAT,CLDR", "adapterTest", "CLDR", "haw", ""); - - //testing the order, variant #4 for the bug 7196799. CLDR's "zh" data - // should be used in "zh_CN" - testRun("CLDR", "adapterTest", "CLDR", "zh", "CN"); - - //testing FALLBACK provider. SPI and invalid one cases. - testRun("SPI", "adapterTest", "FALLBACK", "en", "US"); - testRun("FOO", "adapterTest", "CLDR", "en", "US"); - testRun("BAR,SPI", "adapterTest", "FALLBACK", "en", "US"); - - //testing 7198834 fix. - testRun("HOST", "bug7198834Test", "", "", ""); - - //testing 8000245 fix. - testRun("JRE", "tzNameTest", "Europe/Moscow", "", ""); - testRun("COMPAT", "tzNameTest", "Europe/Moscow", "", ""); - - //testing 8000615 fix. - testRun("JRE", "tzNameTest", "America/Los_Angeles", "", ""); - testRun("COMPAT", "tzNameTest", "America/Los_Angeles", "", ""); - - //testing 8001440 fix. - testRun("CLDR", "bug8001440Test", "", "", ""); - - //testing 8010666 fix. - if (defLang.equals("en")) { - testRun("HOST", "bug8010666Test", "", "", ""); - } - - //testing 8013086 fix. - testRun("JRE,SPI", "bug8013086Test", "ja", "JP", ""); - testRun("COMPAT,SPI", "bug8013086Test", "ja", "JP", ""); - - //testing 8013903 fix. (Windows only) - testRun("HOST,JRE", "bug8013903Test", "", "", ""); - testRun("HOST", "bug8013903Test", "", "", ""); - testRun("HOST,COMPAT", "bug8013903Test", "", "", ""); - - //testing 8027289 fix, if the platform format default is zh_CN - // this assumes Windows' currency symbol for zh_CN is \u00A5, the yen - // (yuan) sign. - if (defFmtLang.equals("zh") && defFmtCtry.equals("CN")) { - testRun("JRE,HOST", "bug8027289Test", "FFE5", "", ""); - testRun("COMPAT,HOST", "bug8027289Test", "FFE5", "", ""); - testRun("HOST", "bug8027289Test", "00A5", "", ""); - } - //testing 8220227 fix. (Windows only) - if (!defLang.equals("en")) { - testRun("HOST", "bug8220227Test", "", "", ""); - } - - //testing 8228465 fix. (Windows only) - testRun("HOST", "bug8228465Test", "", "", ""); - - //testing 8232871 fix. (macOS only) - testRun("HOST", "bug8232871Test", "", "", ""); - - //testing 8232860 fix. (macOS/Windows only) - testRun("HOST", "bug8232860Test", "", "", ""); - - //testing 8245241 fix. - //jdk.lang.Process.allowAmbiguousCommands=false is needed for properly escaping - //double quotes in the string argument. - testRun("FOO", "bug8245241Test", - "Invalid locale provider adapter \"FOO\" ignored.", "", ""); - - //testing 8248695 fix. - testRun("HOST", "bug8248695Test", "", "", ""); + return Stream.of( + Arguments.of("HOST,JRE", param1, defLang, defCtry), + Arguments.of("HOST,JRE", "JRE", param2, param3), + + // Testing SPI is NOT selected, as there is none. + Arguments.of("SPI,JRE", "JRE", "en", "US"), + Arguments.of("SPI,COMPAT", "JRE", "en", "US"), + + // Testing the order, variant #1. This assumes en_GB DateFormat data are + // available both in JRE & CLDR + Arguments.of("CLDR,JRE", "CLDR", "en", "GB"), + Arguments.of("CLDR,COMPAT", "CLDR", "en", "GB"), + + // Testing the order, variant #2. This assumes en_GB DateFormat data are + // available both in JRE & CLDR + Arguments.of("JRE,CLDR", "JRE", "en", "GB"), + Arguments.of("COMPAT,CLDR", "JRE", "en", "GB"), + + // Testing the order, variant #3 for non-existent locale in JRE + // assuming "haw" is not in JRE. + Arguments.of("JRE,CLDR", "CLDR", "haw", ""), + Arguments.of("COMPAT,CLDR", "CLDR", "haw", ""), + + // Testing the order, variant #4 for the bug 7196799. CLDR's "zh" data + // should be used in "zh_CN" + Arguments.of("CLDR", "CLDR", "zh", "CN"), + + // Testing FALLBACK provider. SPI and invalid one cases. + Arguments.of("SPI", "FALLBACK", "en", "US"), + Arguments.of("FOO", "CLDR", "en", "US"), + Arguments.of("BAR,SPI", "FALLBACK", "en", "US") + ); + } - //testing 8257964 fix. (macOS/Windows only) - testRun("HOST", "bug8257964Test", "", "", ""); + /* + * 8010666: Test to ensure correct implementation of Currency/LocaleNameProvider + * in HOST Windows provider (English locale) + */ + @Test + @EnabledOnOs(WINDOWS) + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void currencyNameProviderWindowsHost() throws Throwable { + LocaleProviders.test("HOST", "bug8010666Test"); } - private static void testRun(String prefList, String methodName, - String param1, String param2, String param3) throws Throwable { - - // Build process (without VM flags) - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-ea", "-esa", - "-cp", Utils.TEST_CLASS_PATH, - "-Djava.util.logging.config.class=LocaleProviders$LogConfig", - "-Djava.locale.providers=" + prefList, - "--add-exports=java.base/sun.util.locale.provider=ALL-UNNAMED", - "LocaleProviders", methodName, param1, param2, param3); - // Evaluate process status - int exitCode = ProcessTools.executeCommand(pb).getExitValue(); - if (exitCode != 0) { - throw new RuntimeException("Unexpected exit code: " + exitCode); - } + /* + * 8220227: Ensure Locale::getDisplayCountry does not display error message + * under HOST Windows (non-english locale) + */ + @Test + @EnabledOnOs(WINDOWS) + @DisabledIfSystemProperty(named = "user.language", matches = "en") + public void nonEnglishDisplayCountryHost() throws Throwable { + LocaleProviders.test("HOST", "bug8220227Test"); } } diff --git a/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java new file mode 100644 index 00000000000..46ab5054306 --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java @@ -0,0 +1,51 @@ +/* + * 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 + * 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 8000245 8000615 + * @summary Test any TimeZone Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * providersrc.spi.src.tznp + * providersrc.spi.src.tznp8013086 + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersTimeZone + */ + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersTimeZone { + + /* + * 8000245 and 8000615: Ensure preference is followed, even with a custom + * SPI defined. + */ + @Test + public void timeZoneWithCustomProvider() throws Throwable { + LocaleProviders.test("JRE", "tzNameTest", "Europe/Moscow"); + LocaleProviders.test("COMPAT", "tzNameTest", "Europe/Moscow"); + LocaleProviders.test("JRE", "tzNameTest", "America/Los_Angeles"); + LocaleProviders.test("COMPAT", "tzNameTest", "America/Los_Angeles"); + } +} diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION index c5483b48512..f92096d49aa 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION @@ -1 +1 @@ -tzdata2023c +tzdata2023d diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt index 07c5edbafee..82bad17c553 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt @@ -148,7 +148,6 @@ Link America/Puerto_Rico America/Tortola Link Pacific/Port_Moresby Antarctica/DumontDUrville Link Pacific/Auckland Antarctica/McMurdo Link Asia/Riyadh Antarctica/Syowa -Link Asia/Urumqi Antarctica/Vostok Link Europe/Berlin Arctic/Longyearbyen Link Asia/Riyadh Asia/Aden Link Asia/Qatar Asia/Bahrain diff --git a/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java b/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java new file mode 100644 index 00000000000..ed9897f6291 --- /dev/null +++ b/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java @@ -0,0 +1,67 @@ +/* + * 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 8323659 + * @summary Ensures that the implementation of LTQ add and put methods does + * not call overridable offer. This test specifically asserts implementation + * details of LTQ. It's not that such impl details cannot change, just that + * such a change should be deliberately done with suitable consideration + * to compatibility. + * @run testng SubclassTest + */ + +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TimeUnit; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +@Test +public class SubclassTest { + + public void testPut() { + var queue = new TestLinkedTransferQueue(); + queue.put(new Object()); + assertEquals(queue.size(), 1); + } + + public void testAdd() { + var queue = new TestLinkedTransferQueue(); + queue.add(new Object()); + assertEquals(queue.size(), 1); + } + + public void testTimedOffer() { + var queue = new TestLinkedTransferQueue(); + queue.offer(new Object(), 60, TimeUnit.SECONDS); + assertEquals(queue.size(), 1); + } + + static class TestLinkedTransferQueue extends LinkedTransferQueue { + @Override + public boolean offer(Object obj) { + return false; // simulate fails to add the given obj + } + } +} diff --git a/test/jdk/javax/crypto/KEM/RSA_KEM.java b/test/jdk/javax/crypto/KEM/RSA_KEM.java index c46ded77623..e666df432a6 100644 --- a/test/jdk/javax/crypto/KEM/RSA_KEM.java +++ b/test/jdk/javax/crypto/KEM/RSA_KEM.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 @@ -28,6 +28,7 @@ * @modules java.base/sun.security.jca * java.base/sun.security.rsa * java.base/sun.security.util + * java.base/javax.crypto:+open */ import sun.security.jca.JCAUtil; import sun.security.rsa.RSACore; @@ -88,7 +89,7 @@ public static void main(String[] args) throws Exception { KeyPair kp = g.generateKeyPair(); for (RSAKEMParameterSpec kspec : kspecs) { SecretKey cek = KeyGenerator.getInstance("AES").generateKey(); - KEM kem1 = KEM.getInstance("RSA-KEM", p); + KEM kem1 = getKemImpl(p); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); c.init(Cipher.ENCRYPT_MODE, cek, new IvParameterSpec(iv)); byte[] ciphertext = c.doFinal(msg); @@ -101,7 +102,7 @@ public static void main(String[] args) throws Exception { AlgorithmParameters a = AlgorithmParameters.getInstance("RSA-KEM", p); a.init(enc.params()); - KEM kem2 = KEM.getInstance("RSA-KEM", p); + KEM kem2 = getKemImpl(p); KEM.Decapsulator d = kem2.newDecapsulator(kp.getPrivate(), a.getParameterSpec(AlgorithmParameterSpec.class)); SecretKey k = d.decapsulate(enc.encapsulation(), 0, d.secretSize(), "AES"); Cipher c3 = Cipher.getInstance(kspec.encAlg); @@ -122,6 +123,14 @@ public static void main(String[] args) throws Exception { } } + // To bypass the JCE security provider signature check + private static KEM getKemImpl(Provider p) throws Exception { + var ctor = KEM.class.getDeclaredConstructor( + String.class, KEMSpi.class, Provider.class); + ctor.setAccessible(true); + return ctor.newInstance("RSA-KEM", new KEMImpl(), p); + } + static final String RSA_KEM = "1.2.840.113549.1.9.16.3.14"; static final String KEM_RSA = "1.0.18033.2.2.4"; diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index eb56c087ad6..a468f6b1f1b 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -23,9 +23,10 @@ /* * @test - * @bug 8181157 8202537 8234347 8236548 8261279 + * @bug 8181157 8202537 8234347 8236548 8261279 8322647 * @modules jdk.localedata - * @summary Checks CLDR time zone names are generated correctly at runtime + * @summary Checks CLDR time zone names are generated correctly at + * either build or runtime * @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest */ @@ -45,8 +46,8 @@ @Test public class TimeZoneNamesTest { - @DataProvider(name="noResourceTZs") - Object[][] data() { + @DataProvider + Object[][] sampleTZs() { return new Object[][] { // tzid, locale, style, expected @@ -174,11 +175,49 @@ Object[][] data() { "UTC+03:00", "heure : Istanbul", "UTC+03:00"}, + + // Short names derived from TZDB at build time + {"Europe/Lisbon", Locale.US, "Western European Standard Time", + "WET", + "Western European Summer Time", + "WEST", + "Western European Time", + "WET"}, + {"Atlantic/Azores", Locale.US, "Azores Standard Time", + "GMT-01:00", + "Azores Summer Time", + "GMT", + "Azores Time", + "GMT-01:00"}, + {"Australia/Perth", Locale.US, "Australian Western Standard Time", + "AWST", + "Australian Western Daylight Time", + "AWDT", + "Western Australia Time", + "AWT"}, + {"Africa/Harare", Locale.US, "Central Africa Time", + "CAT", + "Harare Daylight Time", + "CAT", + "Harare Time", + "CAT"}, + {"Europe/Dublin", Locale.US, "Greenwich Mean Time", + "GMT", + "Irish Standard Time", + "IST", + "Dublin Time", + "GMT"}, + {"Pacific/Gambier", Locale.US, "Gambier Time", + "GMT-09:00", + "Gambier Daylight Time", + "GMT-09:00", + "Gambier Time", + "GMT-09:00"}, }; } - @Test(dataProvider="noResourceTZs") + @Test(dataProvider="sampleTZs") public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, String ldst, String sdst, String lgen, String sgen) { // Standard time assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale), lstd); @@ -197,16 +236,14 @@ public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, S @Test public void test_getZoneStrings() { assertFalse( - Arrays.stream(Locale.getAvailableLocales()) + Locale.availableLocales() .limit(30) .peek(l -> System.out.println("Locale: " + l)) .map(l -> DateFormatSymbols.getInstance(l).getZoneStrings()) - .flatMap(zs -> Arrays.stream(zs)) + .flatMap(Arrays::stream) .peek(names -> System.out.println(" tz: " + names[0])) - .flatMap(names -> Arrays.stream(names)) - .filter(name -> Objects.isNull(name) || name.isEmpty()) - .findAny() - .isPresent(), + .flatMap(Arrays::stream) + .anyMatch(name -> Objects.isNull(name) || name.isEmpty()), "getZoneStrings() returned array containing non-empty string element(s)"); } } diff --git a/test/jdk/tools/jar/InputFilesTest.java b/test/jdk/tools/jar/InputFilesTest.java index 3dc08293a76..6a0a7e29021 100644 --- a/test/jdk/tools/jar/InputFilesTest.java +++ b/test/jdk/tools/jar/InputFilesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8165944 + * @bug 8165944 8318971 * @summary test several jar tool input file scenarios with variations on -C * options with/without a --release option. Some input files are * duplicates that sometimes cause exceptions and other times do not, @@ -153,6 +153,84 @@ public void test6() throws IOException { jar("cf test.jar --release 9 -C test1 a -C test2 a"); } + /** + * Containing non-existent file in the file list + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testNonExistentFileInput() throws IOException { + touch("existingTestFile.txt"); + onCompletion = () -> rm("existingTestFile.txt"); + try { + jar("cf test.jar existingTestFile.txt nonExistentTestFile.txt"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + Assert.assertEquals(e.getMessage().trim(), "nonExistentTestFile.txt : no such file or directory"); + Assert.assertTrue(Files.notExists(Path.of("test.jar")), "Jar file should not be created."); + } + } + + /** + * With @File as a part of jar command line, where the File is containing one or more + * non-existent files or directories + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testNonExistentFileInputClassList() throws IOException { + touch("existingTestFile.txt"); + touch("classes.list"); + Files.writeString(Path.of("classes.list"), """ + existingTestFile.txt + nonExistentTestFile.txt + nonExistentDirectory + """); + onCompletion = () -> rm("existingTestFile.txt classes.list"); + try { + jar("cf test.jar @classes.list"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + String msg = e.getMessage().trim(); + Assert.assertTrue(msg.contains("nonExistentTestFile.txt : no such file or directory")); + Assert.assertTrue(msg.trim().contains("nonExistentDirectory : no such file or directory")); + Assert.assertTrue(Files.notExists(Path.of("test.jar")), "Jar file should not be created."); + } + + } + + /** + * Create a jar file; then with @File as a part of jar command line, where the File is containing one or more + * non-existent files or directories + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testUpdateNonExistentFileInputClassList() throws IOException { + touch("existingTestFileUpdate.txt"); + touch("existingTestFileUpdate2.txt"); + touch("classesUpdate.list"); + Files.writeString(Path.of("classesUpdate.list"), """ + existingTestFileUpdate2.txt + nonExistentTestFileUpdate.txt + nonExistentDirectoryUpdate + """); + onCompletion = () -> rm("existingTestFileUpdate.txt existingTestFileUpdate2.txt " + + "classesUpdate.list testUpdate.jar"); + try { + jar("cf testUpdate.jar existingTestFileUpdate.txt"); + Assert.assertTrue(Files.exists(Path.of("testUpdate.jar"))); + jar("uf testUpdate.jar @classesUpdate.list"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + String msg = e.getMessage().trim(); + Assert.assertFalse(msg.contains("existingTestFileUpdate.txt : no such file or directory")); + Assert.assertTrue(msg.contains("nonExistentTestFileUpdate.txt : no such file or directory")); + Assert.assertTrue(msg.trim().contains("nonExistentDirectoryUpdate : no such file or directory")); + } + + } + private Stream mkpath(String... args) { return Arrays.stream(args).map(d -> Paths.get(".", d.split("/"))); } diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java new file mode 100644 index 00000000000..15207909a07 --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java @@ -0,0 +1,145 @@ +/* + * 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.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.test.lib.compiler.CompilerUtils; +import jdk.test.lib.util.FileUtils; + +import static jdk.test.lib.process.ProcessTools.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @test + * @bug 8322809 + * @library /test/lib + * @modules jdk.compiler jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils + * jdk.test.lib.process.ProcessTools + * jdk.test.lib.util.FileUtils + * ModuleMainClassTest + * @run junit ModuleMainClassTest + */ + +public class ModuleMainClassTest { + private static final String JAVA_HOME = System.getProperty("java.home"); + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Path.of(TEST_SRC, "src"); + private static final Path MODS_DIR = Path.of("mods"); + private static final Path JMODS_DIR = Path.of("jmods"); + + private static final Path IMAGE = Path.of("image"); + + // the module names are sorted by the plugin and so these names cover + // the cases that are before and after the elements of `jdk.*` modules + // with main classes + private static String[] modules = new String[] {"com.foo", "net.foo"}; + + private static boolean hasJmods() { + if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) { + System.err.println("Test skipped. NO jmods directory"); + return false; + } + return true; + } + + @BeforeAll + public static void compileAll() throws Throwable { + if (!hasJmods()) return; + + for (String mn : modules) { + Path msrc = SRC_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(msrc, MODS_DIR, + "--module-source-path", SRC_DIR.toString(), + "--add-exports", "java.base/jdk.internal.module=" + mn)); + } + + if (Files.exists(IMAGE)) { + FileUtils.deleteFileTreeUnchecked(IMAGE); + } + + // create JMOD files + Files.createDirectories(JMODS_DIR); + Stream.of(modules).forEach(mn -> + assertTrue(jmod("create", + "--class-path", MODS_DIR.resolve(mn).toString(), + "--main-class", mn + ".Main", + JMODS_DIR.resolve(mn + ".jmod").toString()) == 0) + ); + + // the run-time image created will have 4 modules with main classes + createImage(IMAGE, "com.foo"); + } + + @Test + public void testComFoo() throws Throwable { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), + "-m", "com.foo") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + @Test + public void testNetFoo() throws Throwable { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), + "-m", "net.foo") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") + .orElseThrow(() -> new RuntimeException("jlink tool not found")); + + static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") + .orElseThrow(() -> new RuntimeException("jmod tool not found")); + + private static void createImage(Path outputDir, String... modules) throws Throwable { + assertTrue(JLINK_TOOL.run(System.out, System.out, + "--output", outputDir.toString(), + "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")), + "--module-path", JMODS_DIR.toString()) == 0); + } + + private static int jmod(String... options) { + System.out.println("jmod " + Arrays.asList(options)); + return JMOD_TOOL.run(System.out, System.out, options); + } +} diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java new file mode 100644 index 00000000000..f8b230647fa --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java @@ -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. + */ + +package com.foo; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.stream.Stream; + +/** + * Sanity test if SystemModules pre-resolved at link-time for com.foo + * with main class is loaded properly. + */ +public class Main { + public static void main(String... args) throws Exception { + ModuleDescriptor md = Main.class.getModule().getDescriptor(); + System.out.println(md); + + checkMainClass("com.foo", "com.foo.Main"); + checkMainClass("net.foo", "net.foo.Main"); + Stream.of("jdk.httpserver", "jdk.jfr").forEach(mn -> + ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass() + .orElseThrow(() -> new RuntimeException(mn + " no main class")) + ); + } + + static void checkMainClass(String mn, String mainClass) { + String cn = ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass().get(); + if (!cn.equals(mainClass)) { + throw new RuntimeException("Mismatched main class of module " + mn + ": " + cn + " expected: " + mainClass); + } + } +} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java similarity index 67% rename from test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java index 2ac2064775c..99107602506 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, 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 @@ -21,15 +21,7 @@ * questions. */ -#include - -JNIEXPORT void JNICALL -Java_gc_stress_gclocker_GCLockerStresser_fillWithRandomValues(JNIEnv* env, jclass clz, jbyteArray arr) { - jsize size = (*env)->GetArrayLength(env, arr); - jbyte* p = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); - jsize i; - for (i = 0; i < size; i++) { - p[i] = i % 128; - } - (*env)->ReleasePrimitiveArrayCritical(env, arr, p, 0); +module com.foo { + requires jdk.httpserver; + requires net.foo; } diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java similarity index 61% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java index eeee969a252..360a989d9b3 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, 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 @@ -19,21 +19,8 @@ * 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 gc.stress.gclocker; - -/* - * @test TestGCLockerWithParallel - * @library / - * @requires vm.gc.Parallel - * @summary Stress Parallel's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseParallelGC gc.stress.gclocker.TestGCLockerWithParallel - */ -public class TestGCLockerWithParallel { - public static void main(String[] args) { - String[] testArgs = {"2", "PS Old Gen"}; - TestGCLocker.main(testArgs); - } +module net.foo { + requires jdk.jfr; } diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java new file mode 100644 index 00000000000..c147923e75a --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java @@ -0,0 +1,54 @@ +/* + * 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 net.foo; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.stream.Stream; + +/** + * Sanity test if SystemModules pre-resolved at link-time for net.foo + * with main class is loaded properly. + */ +public class Main { + public static void main(String... args) throws Exception { + ModuleDescriptor md = Main.class.getModule().getDescriptor(); + System.out.println(md); + + checkMainClass("com.foo", "com.foo.Main"); + checkMainClass("net.foo", "net.foo.Main"); + Stream.of("jdk.httpserver", "jdk.jfr").forEach(mn -> + ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass() + .orElseThrow(() -> new RuntimeException(mn + " no main class")) + ); + } + + static void checkMainClass(String mn, String mainClass) { + String cn = ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass().get(); + if (!cn.equals(mainClass)) { + throw new RuntimeException("Mismatched main class of module " + mn + ": " + cn + " expected: " + mainClass); + } + } + +} diff --git a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java index 48106face35..d8539b8c656 100644 --- a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java +++ b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/jdk.internal.shellsupport.doc * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask - * @run testng/timeout=900/othervm JavadocHelperTest + * @run testng/timeout=900/othervm -Xmx1024m JavadocHelperTest */ import java.io.IOException; diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index 51ccbd17d60..98a543e77a9 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8144903 8177466 8191842 8211694 8213725 8239536 8257236 8252409 8294431 + * @bug 8144903 8177466 8191842 8211694 8213725 8239536 8257236 8252409 8294431 8322003 8322532 * @summary Tests for EvaluationState.variables * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -621,4 +621,21 @@ public void varAnonymousClassAndStaticField() { //JDK-8294431 assertEval("var obj = new Object() { public static final String msg = \"hello\"; };"); } + public void underscoreAsLambdaParameter() { //JDK-8322532 + assertAnalyze("Func f = _ -> 0; int i;", + "Func f = _ -> 0;", + " int i;", true); + } + + public void intersectionTypeAsTypeArgument() { //JDK-8322003 + assertEval("interface Shape {}"); + assertEval("record Square(int edge) implements Shape {}"); + assertEval("record Circle(int radius) implements Shape {}"); + assertEval("java.util.function.Consumer printShape = System.out::println;"); + assertEval("Square square = new Square(1);"); + assertEval("Circle circle = new Circle(1);"); + assertEval("var shapes = java.util.List.of(square, circle);"); + assertEval("shapes.forEach(printShape);"); + } + } diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java index b5c94d3ce94..1c040052e69 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java @@ -1,12 +1,12 @@ /* * @test /nodynamiccopyright/ - * @bug 8206986 8222169 8224031 8240964 8267119 8268670 + * @bug 8206986 8222169 8224031 8240964 8267119 8268670 8321582 * @summary Check expression switch works. - * @compile/fail/ref=ExpressionSwitch-old.out --release 9 -XDrawDiagnostics ExpressionSwitch.java * @compile ExpressionSwitch.java * @run main ExpressionSwitch */ +// * @compile/fail/ref=ExpressionSwitch-old.out --release 9 -XDrawDiagnostics ExpressionSwitch.java import java.util.Objects; import java.util.function.Supplier; @@ -35,6 +35,16 @@ private void run() { localClass(T.A); assertEquals(castSwitchExpressions(T.A), "A"); testTypeInference(true, 0); + assertEquals(yieldPrimitiveDotClass("byte"), byte.class); + assertEquals(yieldPrimitiveDotClass("char"), char.class); + assertEquals(yieldPrimitiveDotClass("short"), short.class); + assertEquals(yieldPrimitiveDotClass("int"), int.class); + assertEquals(yieldPrimitiveDotClass("long"), long.class); + assertEquals(yieldPrimitiveDotClass("float"), float.class); + assertEquals(yieldPrimitiveDotClass("double"), double.class); + assertEquals(yieldPrimitiveDotClass("void"), void.class); + assertEquals(yieldPrimitiveDotClass("boolean"), boolean.class); + assertEquals(yieldPrimitiveDotClass("other"), null); } private String print(T t) { @@ -140,6 +150,21 @@ private boolean yieldUnaryNotOperator(String s, boolean b) { }; } + private Class yieldPrimitiveDotClass(String s) { + return switch (s) { + case "byte": yield byte.class; + case "char": yield char.class; + case "short": yield short.class; + case "int": yield int.class; + case "long": yield long.class; + case "float": yield float.class; + case "double": yield double.class; + case "void": yield void.class; + case "boolean": yield boolean.class; + default: yield null; + }; + } + private void localClass(T t) { String good = "good"; class L { diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/ComputePI.java b/test/micro/org/openjdk/bench/vm/compiler/x86/ComputePI.java deleted file mode 100644 index 7d8e479172e..00000000000 --- a/test/micro/org/openjdk/bench/vm/compiler/x86/ComputePI.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.openjdk.bench.vm.compiler; - -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.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; - -import java.util.concurrent.TimeUnit; - -@State(Scope.Thread) -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(value = 3) -public class ComputePI { - - @Benchmark - public double compute_pi_int_dbl() { - double pi = 4.0; - boolean sign = false; - - for (int i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0 / i; - } else { - pi -= 4.0 / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_int_flt() { - float pi = 4.0f; - boolean sign = false; - - for (int i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0f / i; - } else { - pi -= 4.0f / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_long_dbl() { - double pi = 4.0; - boolean sign = false; - - for (long i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0 / i; - } else { - pi -= 4.0 / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_long_flt() { - float pi = 4.0f; - boolean sign = false; - - for (long i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0f / i; - } else { - pi -= 4.0f / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_flt_dbl() { - double pi = 4.0; - boolean sign = false; - - for (float i = 3.0f; i < 1000.0f; i += 2.0f) { - if (sign) { - pi += 4.0 / i; - } else { - pi -= 4.0 / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_dbl_flt() { - float pi = 4.0f; - boolean sign = false; - - for (float i = 3.0f; i < 1000.0f; i += 2.0f) { - if (sign) { - pi += 4.0f / i; - } else { - pi -= 4.0f / i; - } - sign = !sign; - } - return pi; - } -}