diff --git a/make/InterimImage.gmk b/make/InterimImage.gmk index 7e381dbe68829..e046f06051343 100644 --- a/make/InterimImage.gmk +++ b/make/InterimImage.gmk @@ -27,12 +27,13 @@ default: all include $(SPEC) include MakeBase.gmk + +include Execute.gmk include Modules.gmk ################################################################################ -# Use this file inside the image as target for make rule -JIMAGE_TARGET_FILE := bin/java$(EXECUTABLE_SUFFIX) +INTERIM_JLINK_SUPPORT_DIR := $(SUPPORT_OUTPUTDIR)/interim-image-jlink INTERIM_MODULES_LIST := $(call CommaList, $(INTERIM_IMAGE_MODULES)) @@ -42,19 +43,18 @@ JLINK_TOOL := $(JLINK) -J-Djlink.debug=true \ --module-path $(INTERIM_JMODS_DIR) \ --endian $(OPENJDK_BUILD_CPU_ENDIAN) -$(INTERIM_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \ - $(call DependOnVariable, INTERIM_MODULES_LIST) - $(call LogWarn, Creating interim jimage) - $(RM) -r $(INTERIM_IMAGE_DIR) - $(call MakeDir, $(INTERIM_IMAGE_DIR)) - $(call ExecuteWithLog, $(INTERIM_IMAGE_DIR)/jlink, \ - $(JLINK_TOOL) \ - --output $(INTERIM_IMAGE_DIR) \ - --disable-plugin generate-jli-classes \ - --add-modules $(INTERIM_MODULES_LIST)) - $(TOUCH) $@ - -TARGETS += $(INTERIM_IMAGE_DIR)/$(JIMAGE_TARGET_FILE) +$(eval $(call SetupExecute, jlink_interim_image, \ + WARN := Creating interim jimage, \ + DEPS := $(JMODS) $(call DependOnVariable, INTERIM_MODULES_LIST), \ + OUTPUT_DIR := $(INTERIM_IMAGE_DIR), \ + SUPPORT_DIR := $(INTERIM_JLINK_SUPPORT_DIR), \ + PRE_COMMAND := $(RM) -r $(INTERIM_IMAGE_DIR), \ + COMMAND := $(JLINK_TOOL) --output $(INTERIM_IMAGE_DIR) \ + --disable-plugin generate-jli-classes \ + --add-modules $(INTERIM_MODULES_LIST), \ +)) + +TARGETS += $(jlink_interim_image) ################################################################################ diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 89624aeffdd04..d0d11d437e83e 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -75,8 +75,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(hdr, obj); - ldrw(hdr, Address(hdr, Klass::access_flags_offset())); - tstw(hdr, JVM_ACC_IS_VALUE_BASED_CLASS); + ldrb(hdr, Address(hdr, Klass::misc_flags_offset())); + tst(hdr, KlassFlags::_misc_is_value_based_class); br(Assembler::NE, slow_case); } diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 780055a611f3b..cb9eb03c580d2 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -783,8 +783,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label register_finalizer; Register t = r5; __ load_klass(t, r0); - __ ldrw(t, Address(t, Klass::access_flags_offset())); - __ tbnz(t, exact_log2(JVM_ACC_HAS_FINALIZER), register_finalizer); + __ ldrb(t, Address(t, Klass::misc_flags_offset())); + __ tbnz(t, exact_log2(KlassFlags::_misc_has_finalizer), register_finalizer); __ ret(lr); __ bind(register_finalizer); diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 19af03d348806..b4c12ecd4a849 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -64,8 +64,8 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, oop); - ldrw(tmp, Address(tmp, Klass::access_flags_offset())); - tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS); + ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); + tst(tmp, KlassFlags::_misc_is_value_based_class); br(Assembler::NE, cont); } @@ -243,8 +243,8 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(t1, obj); - ldrw(t1, Address(t1, Klass::access_flags_offset())); - tstw(t1, JVM_ACC_IS_VALUE_BASED_CLASS); + ldrb(t1, Address(t1, Klass::misc_flags_offset())); + tst(t1, KlassFlags::_misc_is_value_based_class); br(Assembler::NE, slow_path); } diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index 117168de0c5f0..c6af74c3dcdce 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -690,8 +690,8 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, obj_reg); - ldrw(tmp, Address(tmp, Klass::access_flags_offset())); - tstw(tmp, JVM_ACC_IS_VALUE_BASED_CLASS); + ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); + tst(tmp, KlassFlags::_misc_is_value_based_class); br(Assembler::NE, slow_case); } diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index f7cf99381578b..25eb339bfce71 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2191,9 +2191,9 @@ void TemplateTable::_return(TosState state) __ ldr(c_rarg1, aaddress(0)); __ load_klass(r3, c_rarg1); - __ ldrw(r3, Address(r3, Klass::access_flags_offset())); + __ ldrb(r3, Address(r3, Klass::misc_flags_offset())); Label skip_register_finalizer; - __ tbz(r3, exact_log2(JVM_ACC_HAS_FINALIZER), skip_register_finalizer); + __ tbz(r3, exact_log2(KlassFlags::_misc_has_finalizer), skip_register_finalizer); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), c_rarg1); diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp index f1267587ce4f1..70542d278acf7 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp @@ -195,8 +195,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp2, obj); - ldr_u32(tmp2, Address(tmp2, Klass::access_flags_offset())); - tst(tmp2, JVM_ACC_IS_VALUE_BASED_CLASS); + ldrb(tmp2, Address(tmp2, Klass::misc_flags_offset())); + tst(tmp2, KlassFlags::_misc_is_value_based_class); b(slow_case, ne); } diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index 9862a074a687f..335baf5f16638 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -504,11 +504,11 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { { __ set_info("register_finalizer", dont_gc_arguments); - // Do not call runtime if JVM_ACC_HAS_FINALIZER flag is not set + // Do not call runtime if has_finalizer flag is not set __ load_klass(Rtemp, R0); - __ ldr_u32(Rtemp, Address(Rtemp, Klass::access_flags_offset())); + __ ldrb(Rtemp, Address(Rtemp, Klass::misc_flags_offset())); - __ tst(Rtemp, JVM_ACC_HAS_FINALIZER); + __ tst(Rtemp, KlassFlags::_misc_has_finalizer); __ bx(LR, eq); // Call VM diff --git a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp index 1db30ce5c685d..900bd33fd9d46 100644 --- a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.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 @@ -86,8 +86,8 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(Rscratch, Roop); - ldr_u32(Rscratch, Address(Rscratch, Klass::access_flags_offset())); - tst(Rscratch, JVM_ACC_IS_VALUE_BASED_CLASS); + ldrb(Rscratch, Address(Rscratch, Klass::misc_flags_offset())); + tst(Rscratch, KlassFlags::_misc_is_value_based_class); b(done, ne); } diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 2874abafc4f69..3a81fdddb3c32 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -909,8 +909,8 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) { if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(R0, Robj); - ldr_u32(R0, Address(R0, Klass::access_flags_offset())); - tst(R0, JVM_ACC_IS_VALUE_BASED_CLASS); + ldrb(R0, Address(R0, Klass::misc_flags_offset())); + tst(R0, KlassFlags::_misc_is_value_based_class); b(slow_case, ne); } diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index e657c65958834..80519fd89f426 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2494,8 +2494,8 @@ void TemplateTable::_return(TosState state) { assert(state == vtos, "only valid state"); __ ldr(R1, aaddress(0)); __ load_klass(Rtemp, R1); - __ ldr_u32(Rtemp, Address(Rtemp, Klass::access_flags_offset())); - __ tbz(Rtemp, exact_log2(JVM_ACC_HAS_FINALIZER), skip_register_finalizer); + __ ldrb(Rtemp, Address(Rtemp, Klass::misc_flags_offset())); + __ tbz(Rtemp, exact_log2(KlassFlags::_misc_has_finalizer), skip_register_finalizer); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R1); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 88d635f2b856f..2191b894f6e16 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -1859,7 +1859,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { __ stw(R11_scratch1, simm16_offs, tmp); } #endif - __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + __ call_c(copyfunc_addr, relocInfo::runtime_call_type); __ nand(tmp, R3_RET, R3_RET); __ subf(length, tmp, length); @@ -2057,7 +2057,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { int sco_offset = in_bytes(Klass::super_check_offset_offset()); __ lwz(chk_off, sco_offset, super_k); - __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + __ call_c(copyfunc_addr, relocInfo::runtime_call_type); #ifndef PRODUCT if (PrintC1Statistics) { @@ -2181,7 +2181,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { // Arraycopy stubs takes a length in number of elements, so don't scale it. __ mr(len, length); - __ call_c_with_frame_resize(entry, /*stub does not need resized frame*/ 0); + __ call_c(entry, relocInfo::runtime_call_type); if (stub != nullptr) { __ bind(*stub->continuation()); @@ -2862,7 +2862,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, return; } - __ call_c_with_frame_resize(dest, /*no resizing*/ 0); + __ call_c(dest, relocInfo::runtime_call_type); if (info != nullptr) { add_call_info_here(info); } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index abc439df82793..059bb2eae0c3a 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -86,8 +86,8 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(Rscratch, Roop); - lwz(Rscratch, in_bytes(Klass::access_flags_offset()), Rscratch); - testbitdi(CCR0, R0, Rscratch, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch); + testbitdi(CCR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class)); bne(CCR0, slow_int); } @@ -404,14 +404,3 @@ void C1_MacroAssembler::null_check(Register r, Label* Lnull) { bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::equal), *Lnull); } } - -address C1_MacroAssembler::call_c_with_frame_resize(address dest, int frame_resize) { - if (frame_resize) { resize_frame(-frame_resize, R0); } -#if defined(ABI_ELFv2) - address return_pc = call_c(dest, relocInfo::runtime_call_type); -#else - address return_pc = call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, dest), relocInfo::runtime_call_type); -#endif - if (frame_resize) { resize_frame(frame_resize, R0); } - return return_pc; -} diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp index c0a3dd3b83c60..381cb63f832e4 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.hpp @@ -89,6 +89,5 @@ void null_check(Register r, Label *Lnull = nullptr); - address call_c_with_frame_resize(address dest, int frame_resize); #endif // CPU_PPC_C1_MACROASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index 63914c5d1cb93..adddfda4ee74f 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -62,7 +62,7 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, // ARG1 must hold thread address. mr(R3_ARG1, R16_thread); - address return_pc = call_c_with_frame_resize(entry_point, /*No resize, we have a C compatible frame.*/0); + address return_pc = call_c(entry_point); reset_last_Java_frame(); @@ -479,8 +479,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // Load the klass and check the has finalizer flag. __ load_klass(t, R3_ARG1); - __ lwz(t, in_bytes(Klass::access_flags_offset()), t); - __ testbitdi(CCR0, R0, t, exact_log2(JVM_ACC_HAS_FINALIZER)); + __ lbz(t, in_bytes(Klass::misc_flags_offset()), t); + __ testbitdi(CCR0, R0, t, exact_log2(KlassFlags::_misc_has_finalizer)); // Return if has_finalizer bit == 0 (CR0.eq). __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 3acee737a3add..a29e0810d52ca 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.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. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -135,15 +135,7 @@ void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) // Call the Interpreter::remove_activation_preserving_args_entry() // func to get the address of the same-named entrypoint in the // generated interpreter code. -#if defined(ABI_ELFv2) - call_c(CAST_FROM_FN_PTR(address, - Interpreter::remove_activation_preserving_args_entry), - relocInfo::none); -#else - call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, - Interpreter::remove_activation_preserving_args_entry), - relocInfo::none); -#endif + call_c(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); // Jump to Interpreter::_remove_activation_preserving_args_entry. mtctr(R3_RET); @@ -970,8 +962,8 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, object); - lwz(tmp, in_bytes(Klass::access_flags_offset()), tmp); - testbitdi(CCR0, R0, tmp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp); + testbitdi(CCR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); bne(CCR0, slow_case); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index faca90990c893..8449d74d8a861 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1293,11 +1293,7 @@ void MacroAssembler::call_VM_base(Register oop_result, // ARG1 must hold thread address. mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) address return_pc = call_c(entry_point, relocInfo::none); -#else - address return_pc = call_c((FunctionDescriptor*)entry_point, relocInfo::none); -#endif reset_last_Java_frame(); @@ -1318,11 +1314,7 @@ void MacroAssembler::call_VM_base(Register oop_result, void MacroAssembler::call_VM_leaf_base(address entry_point) { BLOCK_COMMENT("call_VM_leaf {"); -#if defined(ABI_ELFv2) - call_c(entry_point, relocInfo::none); -#else - call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::none); -#endif + call_c(entry_point); BLOCK_COMMENT("} call_VM_leaf"); } @@ -2561,8 +2553,8 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(temp, oop); - lwz(temp, in_bytes(Klass::access_flags_offset()), temp); - testbitdi(flag, R0, temp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbz(temp, in_bytes(Klass::misc_flags_offset()), temp); + testbitdi(flag, R0, temp, exact_log2(KlassFlags::_misc_is_value_based_class)); bne(flag, failure); } @@ -2752,8 +2744,8 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp1, obj); - lwz(tmp1, in_bytes(Klass::access_flags_offset()), tmp1); - testbitdi(flag, R0, tmp1, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbz(tmp1, in_bytes(Klass::misc_flags_offset()), tmp1); + testbitdi(flag, R0, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class)); bne(flag, slow_path); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 9a0cf3d8da0e2..03ad37a4fb04a 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -359,7 +359,7 @@ class MacroAssembler: public Assembler { address call_c(Register function_entry); // For tail calls: only branch, don't link, so callee returns to caller of this function. address call_c_and_return_to_caller(Register function_entry); - address call_c(address function_entry, relocInfo::relocType rt); + address call_c(address function_entry, relocInfo::relocType rt = relocInfo::none); #else // Call a C function via a function descriptor and use full C // calling conventions. Updates and returns _last_calls_return_pc. @@ -367,6 +367,9 @@ class MacroAssembler: public Assembler { // For tail calls: only branch, don't link, so callee returns to caller of this function. address call_c_and_return_to_caller(Register function_descriptor); address call_c(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt); + address call_c(address function_entry, relocInfo::relocType rt = relocInfo::none) { + return call_c((const FunctionDescriptor*)function_entry, rt); + } address call_c_using_toc(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt, Register toc); #endif diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp index 8c3bfd4f37bb1..dbdc16ee5f191 100644 --- a/src/hotspot/cpu/ppc/runtime_ppc.cpp +++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp @@ -99,12 +99,7 @@ void OptoRuntime::generate_exception_blob() { __ set_last_Java_frame(/*sp=*/R1_SP, noreg); __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c((address) OptoRuntime::handle_exception_C, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, OptoRuntime::handle_exception_C), - relocInfo::none); -#endif + __ call_c((address) OptoRuntime::handle_exception_C); address calls_return_pc = __ last_calls_return_pc(); # ifdef ASSERT __ cmpdi(CCR0, R3_RET, 0); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 98610d21b67ba..981f1c7afd2a5 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2444,12 +2444,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // The JNI call // -------------------------------------------------------------------------- -#if defined(ABI_ELFv2) __ call_c(native_func, relocInfo::runtime_call_type); -#else - FunctionDescriptor* fd_native_method = (FunctionDescriptor*) native_func; - __ call_c(fd_native_method, relocInfo::runtime_call_type); -#endif // Now, we are back from the native code. @@ -3455,11 +3450,7 @@ RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address r __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c(runtime_entry, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); -#endif + __ call_c(runtime_entry); // Set an oopmap for the call site. oop_maps->add_gc_map((int)(gc_map_pc - start), map); diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index bb746619616ac..03dca2aeb9b7b 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1464,13 +1464,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // native result across the call. No oop is present. __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), - relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), - relocInfo::none); -#endif + __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); __ bind(sync_check_done); diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 0ee9348dde810..a55f30eb67dc4 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -2130,8 +2130,8 @@ void TemplateTable::_return(TosState state) { // Load klass of this obj. __ load_klass(Rklass, R17_tos); - __ lwz(Rklass_flags, in_bytes(Klass::access_flags_offset()), Rklass); - __ testbitdi(CCR0, R0, Rklass_flags, exact_log2(JVM_ACC_HAS_FINALIZER)); + __ lbz(Rklass_flags, in_bytes(Klass::misc_flags_offset()), Rklass); + __ testbitdi(CCR0, R0, Rklass_flags, exact_log2(KlassFlags::_misc_has_finalizer)); __ bfalse(CCR0, Lskip_register_finalizer); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R17_tos /* obj */); diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index dc1a3d443ac67..1ae64b4f283ba 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -64,8 +64,8 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(hdr, obj); - lwu(hdr, Address(hdr, Klass::access_flags_offset())); - test_bit(temp, hdr, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbu(hdr, Address(hdr, Klass::misc_flags_offset())); + test_bit(temp, hdr, exact_log2(KlassFlags::_misc_is_value_based_class)); bnez(temp, slow_case, true /* is_far */); } diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index 74f303ffb02ad..824d03640517e 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -797,8 +797,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label register_finalizer; Register t = x15; __ load_klass(t, x10); - __ lwu(t, Address(t, Klass::access_flags_offset())); - __ test_bit(t0, t, exact_log2(JVM_ACC_HAS_FINALIZER)); + __ lbu(t, Address(t, Klass::misc_flags_offset())); + __ test_bit(t0, t, exact_log2(KlassFlags::_misc_has_finalizer)); __ bnez(t0, register_finalizer); __ ret(); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index a75bfdfc9dcf7..1e3a8bde064b3 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -68,8 +68,8 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, oop); - lwu(tmp, Address(tmp, Klass::access_flags_offset())); - test_bit(tmp, tmp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbu(tmp, Address(tmp, Klass::misc_flags_offset())); + test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); bnez(tmp, slow_path); } @@ -277,8 +277,8 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp1, obj); - lwu(tmp1, Address(tmp1, Klass::access_flags_offset())); - test_bit(tmp1, tmp1, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbu(tmp1, Address(tmp1, Klass::misc_flags_offset())); + test_bit(tmp1, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class)); bnez(tmp1, slow_path); } diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 06b7b780d139c..3eb7abb5ee3b9 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.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. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -750,8 +750,8 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, obj_reg); - lwu(tmp, Address(tmp, Klass::access_flags_offset())); - test_bit(tmp, tmp, exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + lbu(tmp, Address(tmp, Klass::misc_flags_offset())); + test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); bnez(tmp, slow_case); } diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index fa542343949ac..078f54adc3682 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -2098,9 +2098,9 @@ void TemplateTable::_return(TosState state) { __ ld(c_rarg1, aaddress(0)); __ load_klass(x13, c_rarg1); - __ lwu(x13, Address(x13, Klass::access_flags_offset())); + __ lbu(x13, Address(x13, Klass::misc_flags_offset())); Label skip_register_finalizer; - __ test_bit(t0, x13, exact_log2(JVM_ACC_HAS_FINALIZER)); + __ test_bit(t0, x13, exact_log2(KlassFlags::_misc_has_finalizer)); __ beqz(t0, skip_register_finalizer); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), c_rarg1); diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 13b080678217f..a9140a7925ebd 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -72,7 +72,7 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, Roop); - testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); branch_optimized(Assembler::bcondAllOne, slow_case); } diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp index decb3a1cafc31..41c57043d8234 100644 --- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp +++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -443,7 +443,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // Load the klass and check the has finalizer flag. Register klass = Z_ARG2; __ load_klass(klass, Z_ARG1); - __ testbit(Address(klass, Klass::access_flags_offset()), exact_log2(JVM_ACC_HAS_FINALIZER)); + __ z_tm(Address(klass, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer); __ z_bcr(Assembler::bcondAllZero, Z_R14); // Return if bit is not set. OopMap* oop_map = save_live_registers(sasm); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 0b29c31ec96ef..e56beaa9f569c 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1007,7 +1007,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp, object); - testbit(Address(tmp, Klass::access_flags_offset()), exact_log2(JVM_ACC_IS_VALUE_BASED_CLASS)); + z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); z_btrue(slow_case); } diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index d527b4d2aea11..50de705cd9f0c 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -3507,9 +3507,7 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(temp, oop); - z_l(temp, Address(temp, Klass::access_flags_offset())); - assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction"); - z_nilh(temp, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); + z_tm(Address(temp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); z_brne(done); } @@ -6154,9 +6152,7 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp1, obj); - z_l(tmp1, Address(tmp1, Klass::access_flags_offset())); - assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction"); - z_nilh(tmp1, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); + z_tm(Address(tmp1, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); z_brne(slow_path); } diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index ef68a5ac83ac7..0c9f9e031b06a 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -2321,7 +2321,7 @@ void TemplateTable::_return(TosState state) { assert(state == vtos, "only valid state"); __ z_lg(Rthis, aaddress(0)); __ load_klass(Rklass, Rthis); - __ testbit(Address(Rklass, Klass::access_flags_offset()), exact_log2(JVM_ACC_HAS_FINALIZER)); + __ z_tm(Address(Rklass, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer); __ z_bfalse(skip_register_finalizer); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), Rthis); __ bind(skip_register_finalizer); diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 576592d05aa77..4dcacd00a6339 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -58,8 +58,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(hdr, obj, rscratch1); - movl(hdr, Address(hdr, Klass::access_flags_offset())); - testl(hdr, JVM_ACC_IS_VALUE_BASED_CLASS); + testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); jcc(Assembler::notZero, slow_case); } diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index dc051127feaec..11b39ce15eb1a 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1166,8 +1166,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label register_finalizer; Register t = rsi; __ load_klass(t, rax, rscratch1); - __ movl(t, Address(t, Klass::access_flags_offset())); - __ testl(t, JVM_ACC_HAS_FINALIZER); + __ testb(Address(t, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer); __ jcc(Assembler::notZero, register_finalizer); __ ret(0); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 5dbfdbc225d75..c2801a791cb5a 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -277,8 +277,7 @@ void C2_MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmp if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmpReg, objReg, scrReg); - movl(tmpReg, Address(tmpReg, Klass::access_flags_offset())); - testl(tmpReg, JVM_ACC_IS_VALUE_BASED_CLASS); + testb(Address(tmpReg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); jcc(Assembler::notZero, DONE_LABEL); } @@ -597,8 +596,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(rax_reg, obj, t); - movl(rax_reg, Address(rax_reg, Klass::access_flags_offset())); - testl(rax_reg, JVM_ACC_IS_VALUE_BASED_CLASS); + testb(Address(rax_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); jcc(Assembler::notZero, slow_path); } diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 249506c13ffdf..f4b95d846c61e 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1175,8 +1175,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp_reg, obj_reg, rklass_decode_tmp); - movl(tmp_reg, Address(tmp_reg, Klass::access_flags_offset())); - testl(tmp_reg, JVM_ACC_IS_VALUE_BASED_CLASS); + testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); jcc(Assembler::notZero, slow_case); } diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index fc6844aedd6b2..5e783225fcbfc 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -2579,8 +2579,7 @@ void TemplateTable::_return(TosState state) { Register robj = LP64_ONLY(c_rarg1) NOT_LP64(rax); __ movptr(robj, aaddress(0)); __ load_klass(rdi, robj, rscratch1); - __ movl(rdi, Address(rdi, Klass::access_flags_offset())); - __ testl(rdi, JVM_ACC_HAS_FINALIZER); + __ testb(Address(rdi, Klass::misc_flags_offset()), KlassFlags::_misc_has_finalizer); Label skip_register_finalizer; __ jcc(Assembler::zero, skip_register_finalizer); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 3bc4cac2f06a7..e0740ad7f3124 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -6388,7 +6388,7 @@ instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) ins_pipe(pipe_cmov_reg); %} -instruct cmovL_imm_01(rRegL dst, immI_1 src, rFlagsReg cr, cmpOp cop) +instruct cmovL_imm_01(rRegL dst, immL1 src, rFlagsReg cr, cmpOp cop) %{ predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); @@ -6426,7 +6426,7 @@ instruct cmovL_mem(cmpOp cop, rFlagsReg cr, rRegL dst, memory src) ins_pipe(pipe_cmov_mem); // XXX %} -instruct cmovL_imm_01U(rRegL dst, immI_1 src, rFlagsRegU cr, cmpOpU cop) +instruct cmovL_imm_01U(rRegL dst, immL1 src, rFlagsRegU cr, cmpOpU cop) %{ predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); @@ -6452,7 +6452,7 @@ instruct cmovL_regU(cmpOpU cop, rFlagsRegU cr, rRegL dst, rRegL src) ins_pipe(pipe_cmov_reg); // XXX %} -instruct cmovL_imm_01UCF(rRegL dst, immI_1 src, rFlagsRegUCF cr, cmpOpUCF cop) +instruct cmovL_imm_01UCF(rRegL dst, immL1 src, rFlagsRegUCF cr, cmpOpUCF cop) %{ predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index 6b902e8280244..1d4aecda93642 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -30,9 +30,7 @@ // os::Linux defines the interface to Linux operating systems class os::Linux { - friend class CgroupSubsystem; friend class os; - friend class OSContainer; static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); static int (*_pthread_setname_np)(pthread_t, const char*); @@ -58,7 +56,6 @@ class os::Linux { static julong available_memory(); static julong free_memory(); - static int active_processor_count(); static void initialize_system_info(); @@ -93,6 +90,7 @@ class os::Linux { bool has_steal_ticks; }; + static int active_processor_count(); static void kernel_version(long* major, long* minor); // which_logical_cpu=-1 returns accumulated ticks for all cpus. diff --git a/src/hotspot/os/posix/dtrace/hotspot_jni.d b/src/hotspot/os/posix/dtrace/hotspot_jni.d index eb95b7e4c3a52..c5676921b374d 100644 --- a/src/hotspot/os/posix/dtrace/hotspot_jni.d +++ b/src/hotspot/os/posix/dtrace/hotspot_jni.d @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 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 @@ -19,7 +19,7 @@ * 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. - * + * */ provider hotspot_jni { @@ -129,7 +129,7 @@ provider hotspot_jni { probe CallNonvirtualVoidMethodA__return(); probe CallNonvirtualVoidMethod__entry(void*, void*, void*, uintptr_t); probe CallNonvirtualVoidMethod__return(); - probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t); + probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t); probe CallNonvirtualVoidMethodV__return(); probe CallObjectMethodA__entry(void*, void*, uintptr_t); probe CallObjectMethodA__return(void*); @@ -200,14 +200,14 @@ provider hotspot_jni { probe CallStaticVoidMethodA__entry(void*, void*, uintptr_t); probe CallStaticVoidMethodA__return(); probe CallStaticVoidMethod__entry(void*, void*, uintptr_t); - probe CallStaticVoidMethod__return(); - probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t); + probe CallStaticVoidMethod__return(); + probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t); probe CallStaticVoidMethodV__return(); - probe CallVoidMethodA__entry(void*, void*, uintptr_t); + probe CallVoidMethodA__entry(void*, void*, uintptr_t); probe CallVoidMethodA__return(); - probe CallVoidMethod__entry(void*, void*, uintptr_t); - probe CallVoidMethod__return(); - probe CallVoidMethodV__entry(void*, void*, uintptr_t); + probe CallVoidMethod__entry(void*, void*, uintptr_t); + probe CallVoidMethod__return(); + probe CallVoidMethodV__entry(void*, void*, uintptr_t); probe CallVoidMethodV__return(); probe CreateJavaVM__entry(void**, void**, void*); probe CreateJavaVM__return(uint32_t); @@ -229,7 +229,7 @@ provider hotspot_jni { probe ExceptionCheck__return(uintptr_t); probe ExceptionClear__entry(void*); probe ExceptionClear__return(); - probe ExceptionDescribe__entry(void*); + probe ExceptionDescribe__entry(void*); probe ExceptionDescribe__return(); probe ExceptionOccurred__entry(void*); probe ExceptionOccurred__return(void*); @@ -352,6 +352,8 @@ provider hotspot_jni { probe GetStringUTFChars__return(const char*); probe GetStringUTFLength__entry(void*, void*); probe GetStringUTFLength__return(uintptr_t); + probe GetStringUTFLengthAsLong__entry(void*, void*); + probe GetStringUTFLengthAsLong__return(uintptr_t); probe GetStringUTFRegion__entry(void*, void*, uintptr_t, uintptr_t, char*); probe GetStringUTFRegion__return(); probe GetSuperclass__entry(void*, void*); @@ -388,13 +390,13 @@ provider hotspot_jni { probe NewLocalRef__return(void*); probe NewLongArray__entry(void*, uintptr_t); probe NewLongArray__return(void*); - probe NewObjectA__entry(void*, void*, uintptr_t); + probe NewObjectA__entry(void*, void*, uintptr_t); probe NewObjectA__return(void*); probe NewObjectArray__entry(void*, uintptr_t, void*, void*); probe NewObjectArray__return(void*); - probe NewObject__entry(void*, void*, uintptr_t); + probe NewObject__entry(void*, void*, uintptr_t); probe NewObject__return(void*); - probe NewObjectV__entry(void*, void*, uintptr_t); + probe NewObjectV__entry(void*, void*, uintptr_t); probe NewObjectV__return(void*); probe NewShortArray__entry(void*, uintptr_t); probe NewShortArray__return(void*); @@ -408,7 +410,7 @@ provider hotspot_jni { probe PopLocalFrame__return(void*); probe PushLocalFrame__entry(void*, uint32_t); probe PushLocalFrame__return(uint32_t); - probe RegisterNatives__entry(void*, void*, const void*, uint32_t); + probe RegisterNatives__entry(void*, void*, const void*, uint32_t); probe RegisterNatives__return(uint32_t); probe ReleaseBooleanArrayElements__entry(void*, void*, uintptr_t*, uint32_t); probe ReleaseBooleanArrayElements__return(); @@ -490,13 +492,13 @@ provider hotspot_jni { probe SetStaticShortField__return(); probe Throw__entry(void*, void*); probe Throw__return(intptr_t); - probe ThrowNew__entry(void*, void*, const char*); - probe ThrowNew__return(intptr_t); + probe ThrowNew__entry(void*, void*, const char*); + probe ThrowNew__return(intptr_t); probe ToReflectedField__entry(void*, void*, uintptr_t, uintptr_t); probe ToReflectedField__return(void*); probe ToReflectedMethod__entry(void*, void*, uintptr_t, uintptr_t); probe ToReflectedMethod__return(void*); - probe UnregisterNatives__entry(void*, void*); + probe UnregisterNatives__entry(void*, void*); probe UnregisterNatives__return(uint32_t); }; @@ -505,4 +507,3 @@ provider hotspot_jni { #pragma D attributes Private/Private/Unknown provider hotspot_jni function #pragma D attributes Standard/Standard/Common provider hotspot_jni name #pragma D attributes Evolving/Evolving/Common provider hotspot_jni args - diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 1d1d9d3e1a4ed..a1e0a78837f74 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -5741,11 +5741,23 @@ void Parker::unpark() { SetEvent(_ParkHandle); } +// Platform Mutex/Monitor implementation + +PlatformMutex::PlatformMutex() { + InitializeCriticalSection(&_mutex); +} + PlatformMutex::~PlatformMutex() { DeleteCriticalSection(&_mutex); } -// Platform Monitor implementation +PlatformMonitor::PlatformMonitor() { + InitializeConditionVariable(&_cond); +} + +PlatformMonitor::~PlatformMonitor() { + // There is no DeleteConditionVariable API +} // Must already be locked int PlatformMonitor::wait(uint64_t millis) { diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp index bb2da39d42283..3aa88c36958a7 100644 --- a/src/hotspot/os/windows/os_windows.inline.hpp +++ b/src/hotspot/os/windows/os_windows.inline.hpp @@ -61,18 +61,6 @@ inline bool os::numa_has_group_homing() { return false; } // Platform Mutex/Monitor implementation -inline PlatformMutex::PlatformMutex() { - InitializeCriticalSection(&_mutex); -} - -inline PlatformMonitor::PlatformMonitor() { - InitializeConditionVariable(&_cond); -} - -inline PlatformMonitor::~PlatformMonitor() { - // There is no DeleteConditionVariable API -} - inline void PlatformMutex::lock() { EnterCriticalSection(&_mutex); } diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index dc4475a4b8101..a2e903edc342f 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1389,6 +1389,11 @@ void GraphBuilder::jsr(int dest) { // If the bytecodes are strange (jumping out of a jsr block) then we // might end up trying to re-parse a block containing a jsr which // has already been activated. Watch for this case and bail out. + if (next_bci() >= method()->code_size()) { + // This can happen if the subroutine does not terminate with a ret, + // effectively turning the jsr into a goto. + BAILOUT("too-complicated jsr/ret structure"); + } for (ScopeData* cur_scope_data = scope_data(); cur_scope_data != nullptr && cur_scope_data->parsing_jsr() && cur_scope_data->scope() == scope(); cur_scope_data = cur_scope_data->parent()) { @@ -3736,6 +3741,9 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee, bool ignore_return) { bool GraphBuilder::try_inline_jsr(int jsr_dest_bci) { // Introduce a new callee continuation point - all Ret instructions // will be replaced with Gotos to this point. + if (next_bci() >= method()->code_size()) { + return false; + } BlockBegin* cont = block_at(next_bci()); assert(cont != nullptr, "continuation must exist (BlockListBuilder starts a new block after a jsr"); diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index b2695ac2e7873..f8d24295a12e5 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -463,7 +463,7 @@ void ClassListParser::check_class_name(const char* class_name) { err = "class name too long"; } else { assert(Symbol::max_length() < INT_MAX && len < INT_MAX, "must be"); - if (!UTF8::is_legal_utf8((const unsigned char*)class_name, (int)len, /*version_leq_47*/false)) { + if (!UTF8::is_legal_utf8((const unsigned char*)class_name, len, /*version_leq_47*/false)) { err = "class name is not valid UTF8"; } } @@ -849,4 +849,3 @@ void ClassListParser::parse_constant_pool_tag() { ClassPrelinker::preresolve_field_and_method_cp_entries(THREAD, ik, &preresolve_list); } } - diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 240bb25ae3aa8..a9342eeada48b 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) : AccessFlags access_flags = ik->access_flags(); _flags = ciFlags(access_flags); - _has_finalizer = access_flags.has_finalizer(); + _has_finalizer = ik->has_finalizer(); _has_subklass = flags().is_final() ? subklass_false : subklass_unknown; _init_state = ik->init_state(); _has_nonstatic_fields = ik->has_nonstatic_fields(); diff --git a/src/hotspot/share/ci/ciKlass.cpp b/src/hotspot/share/ci/ciKlass.cpp index 6e70d69f05d8f..efdd2512f9024 100644 --- a/src/hotspot/share/ci/ciKlass.cpp +++ b/src/hotspot/share/ci/ciKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -226,6 +226,15 @@ jint ciKlass::access_flags() { ) } +// ------------------------------------------------------------------ +// ciKlass::misc_flags +klass_flags_t ciKlass::misc_flags() { + assert(is_loaded(), "not loaded"); + GUARDED_VM_ENTRY( + return get_Klass()->misc_flags(); + ) +} + // ------------------------------------------------------------------ // ciKlass::print_impl // diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp index 2dd5a5e2c0b7b..58a62b248a4e8 100644 --- a/src/hotspot/share/ci/ciKlass.hpp +++ b/src/hotspot/share/ci/ciKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,6 +121,9 @@ class ciKlass : public ciType { // Fetch Klass::access_flags. jint access_flags(); + // Fetch Klass::misc_flags. + klass_flags_t misc_flags(); + // What kind of ciObject is this? bool is_klass() const { return true; } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 407078d64fc57..60fed287df594 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -1352,105 +1352,16 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, } -// Field allocation types. Used for computing field offsets. - -enum FieldAllocationType { - STATIC_OOP, // Oops - STATIC_BYTE, // Boolean, Byte, char - STATIC_SHORT, // shorts - STATIC_WORD, // ints - STATIC_DOUBLE, // aligned long or double - NONSTATIC_OOP, - NONSTATIC_BYTE, - NONSTATIC_SHORT, - NONSTATIC_WORD, - NONSTATIC_DOUBLE, - MAX_FIELD_ALLOCATION_TYPE, - BAD_ALLOCATION_TYPE = -1 -}; - -static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = { - BAD_ALLOCATION_TYPE, // 0 - BAD_ALLOCATION_TYPE, // 1 - BAD_ALLOCATION_TYPE, // 2 - BAD_ALLOCATION_TYPE, // 3 - NONSTATIC_BYTE , // T_BOOLEAN = 4, - NONSTATIC_SHORT, // T_CHAR = 5, - NONSTATIC_WORD, // T_FLOAT = 6, - NONSTATIC_DOUBLE, // T_DOUBLE = 7, - NONSTATIC_BYTE, // T_BYTE = 8, - NONSTATIC_SHORT, // T_SHORT = 9, - NONSTATIC_WORD, // T_INT = 10, - NONSTATIC_DOUBLE, // T_LONG = 11, - NONSTATIC_OOP, // T_OBJECT = 12, - NONSTATIC_OOP, // T_ARRAY = 13, - BAD_ALLOCATION_TYPE, // T_VOID = 14, - BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, - BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, - BAD_ALLOCATION_TYPE, // T_METADATA = 17, - BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, - BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, - BAD_ALLOCATION_TYPE, // 0 - BAD_ALLOCATION_TYPE, // 1 - BAD_ALLOCATION_TYPE, // 2 - BAD_ALLOCATION_TYPE, // 3 - STATIC_BYTE , // T_BOOLEAN = 4, - STATIC_SHORT, // T_CHAR = 5, - STATIC_WORD, // T_FLOAT = 6, - STATIC_DOUBLE, // T_DOUBLE = 7, - STATIC_BYTE, // T_BYTE = 8, - STATIC_SHORT, // T_SHORT = 9, - STATIC_WORD, // T_INT = 10, - STATIC_DOUBLE, // T_LONG = 11, - STATIC_OOP, // T_OBJECT = 12, - STATIC_OOP, // T_ARRAY = 13, - BAD_ALLOCATION_TYPE, // T_VOID = 14, - BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, - BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, - BAD_ALLOCATION_TYPE, // T_METADATA = 17, - BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, - BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, -}; - -static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) { - assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values"); - FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)]; - assert(result != BAD_ALLOCATION_TYPE, "bad type"); - return result; -} - -class ClassFileParser::FieldAllocationCount : public ResourceObj { - public: - u2 count[MAX_FIELD_ALLOCATION_TYPE]; - - FieldAllocationCount() { - for (int i = 0; i < MAX_FIELD_ALLOCATION_TYPE; i++) { - count[i] = 0; - } - } - - void update(bool is_static, BasicType type) { - FieldAllocationType atype = basic_type_to_atype(is_static, type); - if (atype != BAD_ALLOCATION_TYPE) { - // Make sure there is no overflow with injected fields. - assert(count[atype] < 0xFFFF, "More than 65535 fields"); - count[atype]++; - } - } -}; - // Side-effects: populates the _fields, _fields_annotations, // _fields_type_annotations fields void ClassFileParser::parse_fields(const ClassFileStream* const cfs, bool is_interface, - FieldAllocationCount* const fac, ConstantPool* cp, const int cp_size, u2* const java_fields_count_ptr, TRAPS) { assert(cfs != nullptr, "invariant"); - assert(fac != nullptr, "invariant"); assert(cp != nullptr, "invariant"); assert(java_fields_count_ptr != nullptr, "invariant"); @@ -1544,8 +1455,10 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const BasicType type = cp->basic_type_for_signature_at(signature_index); - // Update FieldAllocationCount for this kind of field - fac->update(is_static, type); + // Update number of static oop fields. + if (is_static && is_reference_type(type)) { + _static_oop_count++; + } FieldInfo fi(access_flags, name_index, signature_index, constantvalue_index, fieldFlags); fi.set_index(n); @@ -1590,10 +1503,6 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, FieldInfo fi(aflags, (u2)(injected[n].name_index), (u2)(injected[n].signature_index), 0, fflags); fi.set_index(index); _temp_field_info->append(fi); - - // Update FieldAllocationCount for this kind of field - const BasicType type = Signature::basic_type(injected[n].signature()); - fac->update(false, type); index++; } } @@ -4559,7 +4468,8 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) const { assert(_need_verify, "only called when _need_verify is true"); - if (!UTF8::is_legal_utf8(buffer, length, _major_version <= 47)) { + // Note: 0 <= length < 64K, as it comes from a u2 entry in the CP. + if (!UTF8::is_legal_utf8(buffer, static_cast(length), _major_version <= 47)) { classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", THREAD); } } @@ -5116,8 +5026,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // Not yet: supers are done below to support the new subtype-checking fields ik->set_nonstatic_field_size(_field_info->_nonstatic_field_size); ik->set_has_nonstatic_fields(_field_info->_has_nonstatic_fields); - assert(_fac != nullptr, "invariant"); - ik->set_static_oop_field_count(_fac->count[STATIC_OOP]); + ik->set_static_oop_field_count(_static_oop_count); // this transfers ownership of a lot of arrays from // the parser onto the InstanceKlass* @@ -5173,9 +5082,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods); ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods); - if (_is_hidden) { - ik->set_is_hidden(); - } + assert(!_is_hidden || ik->is_hidden(), "must be set already"); // Set PackageEntry for this_klass oop cl = ik->class_loader(); @@ -5361,6 +5268,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _is_hidden(cl_info->is_hidden()), _can_access_vm_annotations(cl_info->can_access_vm_annotations()), _orig_cp_size(0), + _static_oop_count(0), _super_klass(), _cp(nullptr), _fieldinfo_stream(nullptr), @@ -5381,7 +5289,6 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _klass(nullptr), _klass_to_deallocate(nullptr), _parsed_annotations(nullptr), - _fac(nullptr), _field_info(nullptr), _temp_field_info(nullptr), _method_ordering(nullptr), @@ -5707,10 +5614,8 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, assert(_local_interfaces != nullptr, "invariant"); // Fields (offsets are filled in later) - _fac = new FieldAllocationCount(); parse_fields(stream, _access_flags.is_interface(), - _fac, cp, cp_size, &_java_fields_count, @@ -5868,7 +5773,6 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st _itable_size = _access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); - assert(_fac != nullptr, "invariant"); assert(_parsed_annotations != nullptr, "invariant"); _field_info = new FieldLayoutInfo(); diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 69d1f357ca55d..f9ab290f99c4e 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -86,7 +86,6 @@ class ClassFileParser { friend class FieldLayout; class ClassAnnotationCollector; - class FieldAllocationCount; class FieldAnnotationCollector; public: @@ -116,6 +115,7 @@ class ClassFileParser { const bool _is_hidden; const bool _can_access_vm_annotations; int _orig_cp_size; + unsigned int _static_oop_count; // Metadata created before the instance klass is created. Must be deallocated // if not transferred to the InstanceKlass upon successful class loading @@ -141,7 +141,6 @@ class ClassFileParser { InstanceKlass* _klass_to_deallocate; // an InstanceKlass* to be destroyed ClassAnnotationCollector* _parsed_annotations; - FieldAllocationCount* _fac; FieldLayoutInfo* _field_info; GrowableArray* _temp_field_info; const intArray* _method_ordering; @@ -260,7 +259,6 @@ class ClassFileParser { void parse_fields(const ClassFileStream* const cfs, bool is_interface, - FieldAllocationCount* const fac, ConstantPool* cp, const int cp_size, u2* const java_fields_count_ptr, diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index e32d124013d8b..b9a559cf9779f 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -285,8 +285,7 @@ Symbol* SystemDictionary::class_name_symbol(const char* name, Symbol* exception, return nullptr; } // Callers should ensure that the name is never an illegal UTF8 string. - assert(UTF8::is_legal_utf8((const unsigned char*)name, - static_cast(name_len), false), + assert(UTF8::is_legal_utf8((const unsigned char*)name, name_len, false), "Class name is not a valid utf8 string."); // Make a new symbol for the class name. diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 8bb06e6dca4dd..ce7f862a7b6c2 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -274,9 +274,16 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return warn_excluded(k, "Has been redefined"); } if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) { - // These are classes loaded from unsupported locations (such as those loaded by JVMTI native - // agent during dump time). - return warn_excluded(k, "Unsupported location"); + if (k->name()->starts_with("java/lang/invoke/BoundMethodHandle$Species_")) { + // This class is dynamically generated by the JDK + ResourceMark rm; + log_info(cds)("Skipping %s because it is dynamically generated", k->name()->as_C_string()); + return true; // exclude without warning + } else { + // These are classes loaded from unsupported locations (such as those loaded by JVMTI native + // agent during dump time). + return warn_excluded(k, "Unsupported location"); + } } if (k->signers() != nullptr) { // We cannot include signed classes in the archive because the certificates diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 074846e2e7919..260da40b87a42 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -893,7 +893,7 @@ void Dependencies::DepStream::print_dependency(outputStream* st, Klass* witness, void Dependencies::DepStream::initial_asserts(size_t byte_limit) { assert(must_be_in_vm(), "raw oops here"); _byte_limit = byte_limit; - _type = (DepType)(end_marker-1); // defeat "already at end" assert + _type = undefined_dependency; // defeat "already at end" assert assert((_code!=nullptr) + (_deps!=nullptr) == 1, "one or t'other"); } #endif //ASSERT diff --git a/src/hotspot/share/code/dependencies.hpp b/src/hotspot/share/code/dependencies.hpp index 124db0b136933..d11c51a66dc66 100644 --- a/src/hotspot/share/code/dependencies.hpp +++ b/src/hotspot/share/code/dependencies.hpp @@ -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 @@ -103,6 +103,9 @@ class Dependencies: public ResourceObj { // type now includes N, that is, all super types of N. // enum DepType { + // _type is initially set to -1, to prevent "already at end" assert + undefined_dependency = -1, + end_marker = 0, // An 'evol' dependency simply notes that the contents of the diff --git a/src/hotspot/share/compiler/methodLiveness.cpp b/src/hotspot/share/compiler/methodLiveness.cpp index 1b764882d1099..7d65b20a1595e 100644 --- a/src/hotspot/share/compiler/methodLiveness.cpp +++ b/src/hotspot/share/compiler/methodLiveness.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 @@ -222,6 +222,9 @@ void MethodLiveness::init_basic_blocks() { dest = _block_map->at(bytes.get_dest()); assert(dest != nullptr, "branch destination must start a block."); dest->add_normal_predecessor(current_block); + if (bci + Bytecodes::length_for(code) >= method_len) { + break; + } BasicBlock *jsrExit = _block_map->at(current_block->limit_bci()); assert(jsrExit != nullptr, "jsr return bci must start a block."); jsr_exit_list->append(jsrExit); @@ -232,6 +235,9 @@ void MethodLiveness::init_basic_blocks() { dest = _block_map->at(bytes.get_far_dest()); assert(dest != nullptr, "branch destination must start a block."); dest->add_normal_predecessor(current_block); + if (bci + Bytecodes::length_for(code) >= method_len) { + break; + } BasicBlock *jsrExit = _block_map->at(current_block->limit_bci()); assert(jsrExit != nullptr, "jsr return bci must start a block."); jsr_exit_list->append(jsrExit); diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 4c66c526151b9..5789b44e6189e 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -172,7 +172,6 @@ class PrepareRegionsClosure : public G1HeapRegionClosure { bool do_heap_region(G1HeapRegion* hr) { hr->prepare_for_full_gc(); - hr->uninstall_group_cardset(); G1CollectedHeap::heap()->prepare_region_for_full_compaction(hr); _collector->before_marking_update_attribute_table(hr); return false; diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp index 4c93aca84928f..910f878ef7fbf 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp @@ -37,6 +37,8 @@ void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(G1 } bool G1FullGCResetMetadataTask::G1ResetMetadataClosure::do_heap_region(G1HeapRegion* hr) { + hr->uninstall_group_cardset(); + uint const region_idx = hr->hrm_index(); if (!_collector->is_compaction_target(region_idx)) { assert(!hr->is_free(), "all free regions should be compaction targets"); diff --git a/src/hotspot/share/gc/z/zPage.cpp b/src/hotspot/share/gc/z/zPage.cpp index 318b2417ee5ea..bfeda56de37dd 100644 --- a/src/hotspot/share/gc/z/zPage.cpp +++ b/src/hotspot/share/gc/z/zPage.cpp @@ -97,11 +97,6 @@ void ZPage::verify_remset_after_reset(ZPageAge prev_age, ZPageResetType type) { // Old-to-old reset switch (type) { - case ZPageResetType::Splitting: - // Page is on the way to be destroyed or reused, delay - // clearing until the page is reset for Allocation. - break; - case ZPageResetType::InPlaceRelocation: // Relocation failed and page is being compacted in-place. // The remset bits are flipped each young mark start, so @@ -188,11 +183,9 @@ ZPage* ZPage::split(size_t split_of_size) { ZPage* ZPage::split_with_pmem(ZPageType type, const ZPhysicalMemory& pmem) { // Resize this page const ZVirtualMemory vmem = _virtual.split(pmem.size()); + assert(vmem.end() == _virtual.start(), "Should be consecutive"); reset_type_and_size(type_from_size(_virtual.size())); - reset(_age, ZPageResetType::Splitting); - - assert(vmem.end() == _virtual.start(), "Should be consecutive"); log_trace(gc, page)("Split page [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", untype(vmem.start()), diff --git a/src/hotspot/share/gc/z/zPage.hpp b/src/hotspot/share/gc/z/zPage.hpp index e07b338c710e0..3c9b3deda9f07 100644 --- a/src/hotspot/share/gc/z/zPage.hpp +++ b/src/hotspot/share/gc/z/zPage.hpp @@ -44,8 +44,6 @@ enum class ZPageResetType { // Page was not selected for relocation, all objects // stayed, but the page aged. FlipAging, - // The page was split and needs to be reset - Splitting, }; class ZPage : public CHeapObj { diff --git a/src/hotspot/share/gc/z/zRemembered.cpp b/src/hotspot/share/gc/z/zRemembered.cpp index fe60a8dc95052..dc28b6d937d46 100644 --- a/src/hotspot/share/gc/z/zRemembered.cpp +++ b/src/hotspot/share/gc/z/zRemembered.cpp @@ -125,7 +125,7 @@ bool ZRemembered::should_scan_page(ZPage* page) const { return false; } -bool ZRemembered::scan_page(ZPage* page) const { +bool ZRemembered::scan_page_and_clear_remset(ZPage* page) const { const bool can_trust_live_bits = page->is_relocatable() && !ZGeneration::old()->is_phase_mark(); @@ -151,6 +151,20 @@ bool ZRemembered::scan_page(ZPage* page) const { // All objects are dead - do nothing } + if (ZVerifyRemembered) { + // Make sure self healing of pointers is ordered before clearing of + // the previous bits so that ZVerify::after_scan can detect missing + // remset entries accurately. + OrderAccess::storestore(); + } + + // If we have consumed the remset entries above we also clear them. + // The exception is if the page is completely empty/garbage, where we don't + // want to race with an old collection modifying the remset as well. + if (!can_trust_live_bits || page->is_marked()) { + page->clear_remset_previous(); + } + return result; } @@ -500,16 +514,7 @@ class ZRememberedScanMarkFollowTask : public ZRestartableTask { if (page != nullptr) { if (_remembered->should_scan_page(page)) { // Visit all entries pointing into young gen - bool found_roots = _remembered->scan_page(page); - - // ... and as a side-effect clear the previous entries - if (ZVerifyRemembered) { - // Make sure self healing of pointers is ordered before clearing of - // the previous bits so that ZVerify::after_scan can detect missing - // remset entries accurately. - OrderAccess::storestore(); - } - page->clear_remset_previous(); + bool found_roots = _remembered->scan_page_and_clear_remset(page); if (found_roots && !left_marking) { // Follow remembered set when possible diff --git a/src/hotspot/share/gc/z/zRemembered.hpp b/src/hotspot/share/gc/z/zRemembered.hpp index f7c74e8c53157..815d5c787d3fc 100644 --- a/src/hotspot/share/gc/z/zRemembered.hpp +++ b/src/hotspot/share/gc/z/zRemembered.hpp @@ -73,7 +73,7 @@ class ZRemembered { bool should_scan_page(ZPage* page) const; - bool scan_page(ZPage* page) const; + bool scan_page_and_clear_remset(ZPage* page) const; bool scan_forwarding(ZForwarding* forwarding, void* context) const; public: diff --git a/src/hotspot/share/gc/z/zRememberedSet.cpp b/src/hotspot/share/gc/z/zRememberedSet.cpp index cb92e38db2e77..ed1dcfaf14d55 100644 --- a/src/hotspot/share/gc/z/zRememberedSet.cpp +++ b/src/hotspot/share/gc/z/zRememberedSet.cpp @@ -78,8 +78,8 @@ bool ZRememberedSet::is_cleared_previous() const { } void ZRememberedSet::clear_all() { - clear_current(); - clear_previous(); + _bitmap[0].clear_large(); + _bitmap[1].clear_large(); } void ZRememberedSet::clear_current() { diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 1526f81295b2a..df77e8a2882ee 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -274,6 +274,7 @@ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _bitmap, uintx) \ nonstatic_field(Klass, _hash_slot, uint8_t) \ + nonstatic_field(Klass, _misc_flags._flags, u1) \ \ nonstatic_field(LocalVariableTableElement, start_bci, u2) \ nonstatic_field(LocalVariableTableElement, length, u2) \ @@ -482,10 +483,6 @@ declare_constant(JVMCINMethodData::SPECULATION_LENGTH_BITS) \ \ declare_constant(JVM_ACC_WRITTEN_FLAGS) \ - declare_constant(JVM_ACC_HAS_FINALIZER) \ - declare_constant(JVM_ACC_IS_CLONEABLE_FAST) \ - declare_constant(JVM_ACC_IS_HIDDEN_CLASS) \ - declare_constant(JVM_ACC_IS_VALUE_BASED_CLASS) \ declare_constant(FieldInfo::FieldFlags::_ff_injected) \ declare_constant(FieldInfo::FieldFlags::_ff_stable) \ declare_preprocessor_constant("JVM_ACC_VARARGS", JVM_ACC_VARARGS) \ @@ -733,6 +730,10 @@ \ declare_constant(InstanceKlassFlags::_misc_has_nonstatic_concrete_methods) \ declare_constant(InstanceKlassFlags::_misc_declares_nonstatic_concrete_methods) \ + declare_constant(KlassFlags::_misc_is_hidden_class) \ + declare_constant(KlassFlags::_misc_is_value_based_class) \ + declare_constant(KlassFlags::_misc_has_finalizer) \ + declare_constant(KlassFlags::_misc_is_cloneable_fast) \ \ declare_constant(JumpData::taken_off_set) \ declare_constant(JumpData::displacement_off_set) \ diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 650279db1bee3..431c7a0e60387 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2659,8 +2659,8 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl array_klasses()->restore_unshareable_info(class_loader_data(), Handle(), CHECK); } - // Initialize @ValueBased class annotation - if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation()) { + // Initialize @ValueBased class annotation if not already set in the archived klass. + if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation() && !is_value_based()) { set_is_value_based(); } } diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 964bb030b960e..f3b625064fbc7 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -65,7 +65,7 @@ void Klass::set_java_mirror(Handle m) { } bool Klass::is_cloneable() const { - return _access_flags.is_cloneable_fast() || + return _misc_flags.is_cloneable_fast() || is_subtype_of(vmClasses::Cloneable_klass()); } @@ -76,7 +76,7 @@ void Klass::set_is_cloneable() { } else if (is_instance_klass() && InstanceKlass::cast(this)->reference_type() != REF_NONE) { // Reference cloning should not be intrinsified and always happen in JVM_Clone. } else { - _access_flags.set_is_cloneable_fast(); + _misc_flags.set_is_cloneable_fast(true); } } @@ -975,6 +975,7 @@ void Klass::oop_print_on(oop obj, outputStream* st) { // print class st->print(BULLET"klass: "); obj->klass()->print_value_on(st); + st->print(BULLET"flags: "); _misc_flags.print_on(st); st->cr(); st->cr(); } diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 6ec6ac889be71..ce74830a3112a 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -27,6 +27,7 @@ #include "memory/iterator.hpp" #include "memory/memRegion.hpp" +#include "oops/klassFlags.hpp" #include "oops/markWord.hpp" #include "oops/metadata.hpp" #include "oops/oop.hpp" @@ -165,6 +166,8 @@ class Klass : public Metadata { // Keep it away from the beginning of a Klass to avoid cacheline // contention that may happen when a nearby object is modified. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. + // Some flags created by the JVM, not in the class file itself, + // are in _misc_flags below. JFR_ONLY(DEFINE_TRACE_ID_FIELD;) @@ -194,6 +197,8 @@ class Klass : public Metadata { }; #endif + KlassFlags _misc_flags; + CDS_JAVA_HEAP_ONLY(int _archived_mirror_index;) protected: @@ -428,6 +433,7 @@ class Klass : public Metadata { static ByteSize next_sibling_offset() { return byte_offset_of(Klass, _next_sibling); } #endif static ByteSize bitmap_offset() { return byte_offset_of(Klass, _bitmap); } + static ByteSize misc_flags_offset() { return byte_offset_of(Klass, _misc_flags._flags); } // Unpacking layout_helper: static const int _lh_neutral_value = 0; // neutral non-array non-instance value @@ -692,12 +698,14 @@ class Klass : public Metadata { bool is_super() const { return _access_flags.is_super(); } bool is_synthetic() const { return _access_flags.is_synthetic(); } void set_is_synthetic() { _access_flags.set_is_synthetic(); } - bool has_finalizer() const { return _access_flags.has_finalizer(); } - void set_has_finalizer() { _access_flags.set_has_finalizer(); } - bool is_hidden() const { return access_flags().is_hidden_class(); } - void set_is_hidden() { _access_flags.set_is_hidden_class(); } - bool is_value_based() { return _access_flags.is_value_based_class(); } - void set_is_value_based() { _access_flags.set_is_value_based_class(); } + bool has_finalizer() const { return _misc_flags.has_finalizer(); } + void set_has_finalizer() { _misc_flags.set_has_finalizer(true); } + bool is_hidden() const { return _misc_flags.is_hidden_class(); } + void set_is_hidden() { _misc_flags.set_is_hidden_class(true); } + bool is_value_based() const { return _misc_flags.is_value_based_class(); } + void set_is_value_based() { _misc_flags.set_is_value_based_class(true); } + + klass_flags_t misc_flags() const { return _misc_flags.value(); } inline bool is_non_strong_hidden() const; diff --git a/src/hotspot/share/oops/klass.inline.hpp b/src/hotspot/share/oops/klass.inline.hpp index a72868a08d890..f549940ef9595 100644 --- a/src/hotspot/share/oops/klass.inline.hpp +++ b/src/hotspot/share/oops/klass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,7 @@ inline oop Klass::klass_holder() const { } inline bool Klass::is_non_strong_hidden() const { - return access_flags().is_hidden_class() && - class_loader_data()->has_class_mirror_holder(); + return is_hidden() && class_loader_data()->has_class_mirror_holder(); } // Iff the class loader (or mirror for non-strong hidden classes) is alive the diff --git a/src/hotspot/share/oops/klassFlags.cpp b/src/hotspot/share/oops/klassFlags.cpp new file mode 100644 index 0000000000000..6399762e8df56 --- /dev/null +++ b/src/hotspot/share/oops/klassFlags.cpp @@ -0,0 +1,34 @@ +/* + * 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 "precompiled.hpp" +#include "oops/klassFlags.hpp" +#include "utilities/ostream.hpp" + +void KlassFlags::print_on(outputStream* st) const { +#define KLASS_FLAGS_PRINT(name, ignore) \ + if (name()) st->print(#name " "); + KLASS_FLAGS_DO(KLASS_FLAGS_PRINT) +#undef KLASS_FLAGS_PRINT +} diff --git a/src/hotspot/share/oops/klassFlags.hpp b/src/hotspot/share/oops/klassFlags.hpp new file mode 100644 index 0000000000000..3e71bb3c1b3cc --- /dev/null +++ b/src/hotspot/share/oops/klassFlags.hpp @@ -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. + * + */ + +#ifndef SHARE_OOPS_KLASSFLAGS_HPP +#define SHARE_OOPS_KLASSFLAGS_HPP + +#include "utilities/globalDefinitions.hpp" + +class outputStream; + +// The Klass class contains only parse-time flags and are used by generated code, even though +// most apply to InstanceKlass, access is more straightforward through Klass pointers. +// These flags are JVM internal and not part of the AccessFlags classfile specification. + +using klass_flags_t = u1; + +class KlassFlags { + friend class VMStructs; + friend class JVMCIVMStructs; + + public: +#define KLASS_FLAGS_DO(flag) \ + flag(is_hidden_class , 1 << 0) \ + flag(is_value_based_class , 1 << 1) \ + flag(has_finalizer , 1 << 2) \ + flag(is_cloneable_fast , 1 << 3) \ + /* end of list */ + +#define KLASS_FLAGS_ENUM_NAME(name, value) _misc_##name = value, + enum { + KLASS_FLAGS_DO(KLASS_FLAGS_ENUM_NAME) + }; +#undef KLASS_FLAGS_ENUM_NAME + + // These flags are write-once before the class is published and then read-only + // so don't require atomic updates. + klass_flags_t _flags; + + public: + KlassFlags() : _flags(0) {} + + klass_flags_t value() const { return _flags; } + + // Create getters and setters for the flag values. +#define KLASS_FLAGS_GET_SET(name, ignore) \ + bool name() const { return (_flags & _misc_##name) != 0; } \ + void set_##name(bool b) { \ + assert(!name(), "set once"); \ + if (b) _flags |= _misc_##name; \ + } + KLASS_FLAGS_DO(KLASS_FLAGS_GET_SET) +#undef KLASS_FLAGS_GET_SET + + void print_on(outputStream* st) const; +}; + +#endif // SHARE_OOPS_KLASSFLAGS_HPP diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index a9d73364e2d00..0ea3bfd122af0 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1701,6 +1701,8 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::access_flags_offset())) alias_type(idx)->set_rewritable(false); + if (flat->offset() == in_bytes(Klass::misc_flags_offset())) + alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::java_mirror_offset())) alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::secondary_super_cache_offset())) @@ -5196,7 +5198,20 @@ void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { ss.print(" %d", iter); } if (n != nullptr) { - ss.print(": %d %s ", n->_idx, NodeClassNames[n->Opcode()]); + ss.print(": %d %s", n->_idx, NodeClassNames[n->Opcode()]); + if (n->is_Call()) { + CallNode* call = n->as_Call(); + if (call->_name != nullptr) { + // E.g. uncommon traps etc. + ss.print(" - %s", call->_name); + } else if (call->is_CallJava()) { + CallJavaNode* call_java = call->as_CallJava(); + if (call_java->method() != nullptr) { + ss.print(" -"); + call_java->method()->print_short_name(&ss); + } + } + } } const char* name = ss.as_string(); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 24901855b91a1..c95a450272989 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -3860,13 +3860,14 @@ Node* LibraryCallKit::load_klass_from_mirror_common(Node* mirror, } //--------------------(inline_native_Class_query helpers)--------------------- -// Use this for JVM_ACC_INTERFACE, JVM_ACC_IS_CLONEABLE_FAST, JVM_ACC_HAS_FINALIZER. +// Use this for JVM_ACC_INTERFACE. // Fall through if (mods & mask) == bits, take the guard otherwise. -Node* LibraryCallKit::generate_access_flags_guard(Node* kls, int modifier_mask, int modifier_bits, RegionNode* region) { +Node* LibraryCallKit::generate_klass_flags_guard(Node* kls, int modifier_mask, int modifier_bits, RegionNode* region, + ByteSize offset, const Type* type, BasicType bt) { // Branch around if the given klass has the given modifier bit set. // Like generate_guard, adds a new path onto the region. - Node* modp = basic_plus_adr(kls, in_bytes(Klass::access_flags_offset())); - Node* mods = make_load(nullptr, modp, TypeInt::INT, T_INT, MemNode::unordered); + Node* modp = basic_plus_adr(kls, in_bytes(offset)); + Node* mods = make_load(nullptr, modp, type, bt, MemNode::unordered); Node* mask = intcon(modifier_mask); Node* bits = intcon(modifier_bits); Node* mbit = _gvn.transform(new AndINode(mods, mask)); @@ -3875,10 +3876,18 @@ Node* LibraryCallKit::generate_access_flags_guard(Node* kls, int modifier_mask, return generate_fair_guard(bol, region); } Node* LibraryCallKit::generate_interface_guard(Node* kls, RegionNode* region) { - return generate_access_flags_guard(kls, JVM_ACC_INTERFACE, 0, region); + return generate_klass_flags_guard(kls, JVM_ACC_INTERFACE, 0, region, + Klass::access_flags_offset(), TypeInt::INT, T_INT); } + +// Use this for testing if Klass is_hidden, has_finalizer, and is_cloneable_fast. +Node* LibraryCallKit::generate_misc_flags_guard(Node* kls, int modifier_mask, int modifier_bits, RegionNode* region) { + return generate_klass_flags_guard(kls, modifier_mask, modifier_bits, region, + Klass::misc_flags_offset(), TypeInt::UBYTE, T_BOOLEAN); +} + Node* LibraryCallKit::generate_hidden_class_guard(Node* kls, RegionNode* region) { - return generate_access_flags_guard(kls, JVM_ACC_IS_HIDDEN_CLASS, 0, region); + return generate_misc_flags_guard(kls, KlassFlags::_misc_is_hidden_class, 0, region); } //-------------------------inline_native_Class_query------------------- @@ -5320,12 +5329,12 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { // The object must be easily cloneable and must not have a finalizer. // Both of these conditions may be checked in a single test. // We could optimize the test further, but we don't care. - generate_access_flags_guard(obj_klass, - // Test both conditions: - JVM_ACC_IS_CLONEABLE_FAST | JVM_ACC_HAS_FINALIZER, - // Must be cloneable but not finalizer: - JVM_ACC_IS_CLONEABLE_FAST, - slow_region); + generate_misc_flags_guard(obj_klass, + // Test both conditions: + KlassFlags::_misc_is_cloneable_fast | KlassFlags::_misc_has_finalizer, + // Must be cloneable but not finalizer: + KlassFlags::_misc_is_cloneable_fast, + slow_region); } if (!stopped()) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 4ae9d0216e9fd..dd74734802f65 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -156,9 +156,11 @@ class LibraryCallKit : public GraphKit { region, null_path, offset); } - Node* generate_access_flags_guard(Node* kls, - int modifier_mask, int modifier_bits, - RegionNode* region); + Node* generate_klass_flags_guard(Node* kls, int modifier_mask, int modifier_bits, RegionNode* region, + ByteSize offset, const Type* type, BasicType bt); + Node* generate_misc_flags_guard(Node* kls, + int modifier_mask, int modifier_bits, + RegionNode* region); Node* generate_interface_guard(Node* kls, RegionNode* region); Node* generate_hidden_class_guard(Node* kls, RegionNode* region); Node* generate_array_guard(Node* kls, RegionNode* region) { diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index b4c134570e63f..3128e23d79c49 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -4511,23 +4511,6 @@ bool PhaseIdealLoop::process_expensive_nodes() { return progress; } -#ifdef ASSERT -// Goes over all children of the root of the loop tree. Check if any of them have a path -// down to Root, that does not go via a NeverBranch exit. -bool PhaseIdealLoop::only_has_infinite_loops() { - ResourceMark rm; - Unique_Node_List worklist; - // start traversal at all loop heads of first-level loops - for (IdealLoopTree* l = _ltree_root->_child; l != nullptr; l = l->_next) { - Node* head = l->_head; - assert(head->is_Region(), ""); - worklist.push(head); - } - return RegionNode::are_all_nodes_in_infinite_subgraph(worklist); -} -#endif - - //============================================================================= //----------------------------build_and_optimize------------------------------- // Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to @@ -4586,13 +4569,9 @@ void PhaseIdealLoop::build_and_optimize() { return; } - // Verify that the has_loops() flag set at parse time is consistent - // with the just built loop tree. With infinite loops, it could be - // that one pass of loop opts only finds infinite loops, clears the - // has_loops() flag but adds NeverBranch nodes so the next loop opts - // verification pass finds a non empty loop tree. When the back edge + // Verify that the has_loops() flag set at parse time is consistent with the just built loop tree. When the back edge // is an exception edge, parsing doesn't set has_loops(). - assert(_ltree_root->_child == nullptr || C->has_loops() || only_has_infinite_loops() || C->has_exception_backedge(), "parsing found no loops but there are some"); + assert(_ltree_root->_child == nullptr || C->has_loops() || C->has_exception_backedge(), "parsing found no loops but there are some"); // No loops after all if( !_ltree_root->_child && !_verify_only ) C->set_has_loops(false); @@ -5425,7 +5404,7 @@ void PhaseIdealLoop::build_loop_tree() { if ( bltstack.length() == stack_size ) { // There were no additional children, post visit node now (void)bltstack.pop(); // Remove node from stack - pre_order = build_loop_tree_impl( n, pre_order ); + pre_order = build_loop_tree_impl(n, pre_order); // Check for bailout if (C->failing()) { return; @@ -5443,7 +5422,7 @@ void PhaseIdealLoop::build_loop_tree() { } //------------------------------build_loop_tree_impl--------------------------- -int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { +int PhaseIdealLoop::build_loop_tree_impl(Node* n, int pre_order) { // ---- Post-pass Work ---- // Pre-walked but not post-walked nodes need a pre_order number. @@ -5454,24 +5433,24 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // for it. Then find the tightest enclosing loop for the self Node. for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* m = n->fast_out(i); // Child - if( n == m ) continue; // Ignore control self-cycles - if( !m->is_CFG() ) continue;// Ignore non-CFG edges + if (n == m) continue; // Ignore control self-cycles + if (!m->is_CFG()) continue;// Ignore non-CFG edges IdealLoopTree *l; // Child's loop - if( !is_postvisited(m) ) { // Child visited but not post-visited? + if (!is_postvisited(m)) { // Child visited but not post-visited? // Found a backedge - assert( get_preorder(m) < pre_order, "should be backedge" ); + assert(get_preorder(m) < pre_order, "should be backedge"); // Check for the RootNode, which is already a LoopNode and is allowed // to have multiple "backedges". - if( m == C->root()) { // Found the root? + if (m == C->root()) { // Found the root? l = _ltree_root; // Root is the outermost LoopNode } else { // Else found a nested loop // Insert a LoopNode to mark this loop. l = new IdealLoopTree(this, m, n); } // End of Else found a nested loop - if( !has_loop(m) ) // If 'm' does not already have a loop set + if (!has_loop(m)) { // If 'm' does not already have a loop set set_loop(m, l); // Set loop header to loop now - + } } else { // Else not a nested loop if (!_loop_or_ctrl[m->_idx]) continue; // Dead code has no loop IdealLoopTree* m_loop = get_loop(m); @@ -5480,23 +5459,17 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // is a member of some outer enclosing loop. Since there are no // shared headers (I've split them already) I only need to go up // at most 1 level. - while( l && l->_head == m ) // Successor heads loop? + while (l && l->_head == m) { // Successor heads loop? l = l->_parent; // Move up 1 for me + } // If this loop is not properly parented, then this loop // has no exit path out, i.e. its an infinite loop. - if( !l ) { + if (!l) { // Make loop "reachable" from root so the CFG is reachable. Basically // insert a bogus loop exit that is never taken. 'm', the loop head, // points to 'n', one (of possibly many) fall-in paths. There may be // many backedges as well. - // Here I set the loop to be the root loop. I could have, after - // inserting a bogus loop exit, restarted the recursion and found my - // new loop exit. This would make the infinite loop a first-class - // loop and it would then get properly optimized. What's the use of - // optimizing an infinite loop? - l = _ltree_root; // Oops, found infinite loop - if (!_verify_only) { // Insert the NeverBranch between 'm' and it's control user. NeverBranchNode *iff = new NeverBranchNode( m ); @@ -5520,7 +5493,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // Now create the never-taken loop exit Node *if_f = new CProjNode( iff, 1 ); _igvn.register_new_node_with_optimizer(if_f); - set_loop(if_f, l); + set_loop(if_f, _ltree_root); // Find frame ptr for Halt. Relies on the optimizer // V-N'ing. Easier and quicker than searching through // the program structure. @@ -5529,10 +5502,27 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // Halt & Catch Fire Node* halt = new HaltNode(if_f, frame, "never-taken loop exit reached"); _igvn.register_new_node_with_optimizer(halt); - set_loop(halt, l); + set_loop(halt, _ltree_root); _igvn.add_input_to(C->root(), halt); } set_loop(C->root(), _ltree_root); + // move to outer most loop with same header + l = m_loop; + while (true) { + IdealLoopTree* next = l->_parent; + if (next == nullptr || next->_head != m) { + break; + } + l = next; + } + // properly insert infinite loop in loop tree + sort(_ltree_root, l); + // fix child link from parent + IdealLoopTree* p = l->_parent; + l->_next = p->_child; + p->_child = l; + // code below needs enclosing loop + l = l->_parent; } } if (is_postvisited(l->_head)) { @@ -5586,7 +5576,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { assert( get_loop(n) == innermost, "" ); IdealLoopTree *p = innermost->_parent; IdealLoopTree *l = innermost; - while( p && l->_head == n ) { + while (p && l->_head == n) { l->_next = p->_child; // Put self on parents 'next child' p->_child = l; // Make self as first child of parent l = p; // Now walk up the parent chain @@ -5600,7 +5590,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) { // Record tightest enclosing loop for self. Mark as post-visited. set_loop(n, innermost); // Also record has_call flag early on - if( innermost ) { + if (innermost) { if( n->is_Call() && !n->is_CallLeaf() && !n->is_macro() ) { // Do not count uncommon calls if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 369f446adbbd7..6b2ad120a6380 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -966,10 +966,6 @@ class PhaseIdealLoop : public PhaseTransform { const Node_List& old_new); void insert_loop_limit_check_predicate(ParsePredicateSuccessProj* loop_limit_check_parse_proj, Node* cmp_limit, Node* bol); -#ifdef ASSERT - bool only_has_infinite_loops(); -#endif - void log_loop_tree(); public: @@ -1076,7 +1072,7 @@ class PhaseIdealLoop : public PhaseTransform { // Place 'n' in some loop nest, where 'n' is a CFG node void build_loop_tree(); - int build_loop_tree_impl( Node *n, int pre_order ); + int build_loop_tree_impl(Node* n, int pre_order); // Insert loop into the existing loop tree. 'innermost' is a leaf of the // loop tree, not the root. IdealLoopTree *sort( IdealLoopTree *loop, IdealLoopTree *innermost ); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 2d79857b62a78..eee14e5ba03f1 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1981,6 +1981,12 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, assert(this->Opcode() == Op_LoadI, "must load an int from _access_flags"); return TypeInt::make(klass->access_flags()); } + if (tkls->offset() == in_bytes(Klass::misc_flags_offset())) { + // The field is Klass::_misc_flags. Return its (constant) value. + // (Folds up the 2nd indirection in Reflection.getClassAccessFlags(aClassConstant).) + assert(this->Opcode() == Op_LoadUB, "must load an unsigned byte from _misc_flags"); + return TypeInt::make(klass->misc_flags()); + } if (tkls->offset() == in_bytes(Klass::layout_helper_offset())) { // The field is Klass::_layout_helper. Return its constant value if known. assert(this->Opcode() == Op_LoadI, "must load an int from _layout_helper"); diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 05627450585ff..d4a6a9ce5b7a9 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1651,7 +1651,7 @@ void Parse::merge_new_path(int target_bci) { // The ex_oop must be pushed on the stack, unlike throw_to_exit. void Parse::merge_exception(int target_bci) { #ifdef ASSERT - if (target_bci < bci()) { + if (target_bci <= bci()) { C->set_exception_backedge(); } #endif @@ -2123,10 +2123,10 @@ void Parse::call_register_finalizer() { Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() ); Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), klass_addr, TypeInstPtr::KLASS)); - Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset())); - Node* access_flags = make_load(nullptr, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered); + Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::misc_flags_offset())); + Node* access_flags = make_load(nullptr, access_flags_addr, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered); - Node* mask = _gvn.transform(new AndINode(access_flags, intcon(JVM_ACC_HAS_FINALIZER))); + Node* mask = _gvn.transform(new AndINode(access_flags, intcon(KlassFlags::_misc_has_finalizer))); Node* check = _gvn.transform(new CmpINode(mask, intcon(0))); Node* test = _gvn.transform(new BoolNode(check, BoolTest::ne)); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 8a20d5f85b012..fbb2c6e3e08eb 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -102,7 +102,7 @@ #include "jfr/jfr.hpp" #endif -static jint CurrentVersion = JNI_VERSION_21; +static jint CurrentVersion = JNI_VERSION_24; #if defined(_WIN32) && !defined(USE_VECTORED_EXCEPTION_HANDLING) extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); @@ -2221,13 +2221,21 @@ JNI_END JNI_ENTRY(jsize, jni_GetStringUTFLength(JNIEnv *env, jstring string)) - HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY(env, string); + HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY(env, string); oop java_string = JNIHandles::resolve_non_null(string); jsize ret = java_lang_String::utf8_length_as_int(java_string); HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN(ret); return ret; JNI_END +JNI_ENTRY(jlong, jni_GetStringUTFLengthAsLong(JNIEnv *env, jstring string)) + HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY(env, string); + oop java_string = JNIHandles::resolve_non_null(string); + size_t ret = java_lang_String::utf8_length(java_string); + HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN(ret); +return checked_cast(ret); +JNI_END + JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy)) HOTSPOT_JNI_GETSTRINGUTFCHARS_ENTRY(env, string, (uintptr_t *) isCopy); @@ -3398,7 +3406,11 @@ struct JNINativeInterface_ jni_NativeInterface = { // Virtual threads - jni_IsVirtualThread + jni_IsVirtualThread, + + // Large UTF8 support + + jni_GetStringUTFLengthAsLong }; diff --git a/src/hotspot/share/prims/jniCheck.cpp b/src/hotspot/share/prims/jniCheck.cpp index 0da0cbbd63946..8c1f9f53b343d 100644 --- a/src/hotspot/share/prims/jniCheck.cpp +++ b/src/hotspot/share/prims/jniCheck.cpp @@ -475,7 +475,7 @@ void jniCheck::validate_class_descriptor(JavaThread* thr, const char* name) { } // Verify that the class name given is a valid utf8 string - if (!UTF8::is_legal_utf8((const unsigned char*)name, (int)strlen(name), false)) { + if (!UTF8::is_legal_utf8((const unsigned char*)name, strlen(name), false)) { char msg[JVM_MAXPATHLEN]; jio_snprintf(msg, JVM_MAXPATHLEN, "%s%s%s", fatal_non_utf8_class_name1, name, fatal_non_utf8_class_name2); ReportJNIFatalError(thr, msg); @@ -1511,6 +1511,27 @@ JNI_ENTRY_CHECKED(jsize, checkString(thr, str); ) jsize result = UNCHECKED()->GetStringUTFLength(env,str); + jlong full_length = UNCHECKED()->GetStringUTFLengthAsLong(env,str); + if (full_length > result) { + ResourceMark rm(thr); + stringStream ss; + ss.print("WARNING: large String with modified UTF-8 length " JLONG_FORMAT + " is reporting a reduced length of %d - use GetStringUTFLengthAsLong instead", + full_length, result); + NativeReportJNIWarning(thr, ss.as_string()); + } + functionExit(thr); + return result; +JNI_END + +JNI_ENTRY_CHECKED(jlong, + checked_jni_GetStringUTFLengthAsLong(JNIEnv *env, + jstring str)) + functionEnter(thr); + IN_VM( + checkString(thr, str); + ) + jlong result = UNCHECKED()->GetStringUTFLengthAsLong(env,str); functionExit(thr); return result; JNI_END @@ -2283,7 +2304,12 @@ struct JNINativeInterface_ checked_jni_NativeInterface = { // Virtual threads - checked_jni_IsVirtualThread + checked_jni_IsVirtualThread, + + // Large UTF8 support + + checked_jni_GetStringUTFLengthAsLong + }; diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 6425f5f583f36..bf9874956bae2 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -809,7 +809,7 @@ JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env, // into the constant pool. return nullptr; } - assert(UTF8::is_legal_utf8((const unsigned char*)name, (int)strlen(name), false), "illegal UTF name"); + assert(UTF8::is_legal_utf8((const unsigned char*)name, strlen(name), false), "illegal UTF name"); TempNewSymbol h_name = SymbolTable::new_symbol(name); Klass* k = SystemDictionary::resolve_or_null(h_name, CHECK_NULL); diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index ea18ff3a00686..af904bdcfcd28 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -984,6 +984,7 @@ jboolean Threads::is_supported_jni_version(jint version) { if (version == JNI_VERSION_19) return JNI_TRUE; if (version == JNI_VERSION_20) return JNI_TRUE; if (version == JNI_VERSION_21) return JNI_TRUE; + if (version == JNI_VERSION_24) return JNI_TRUE; return JNI_FALSE; } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index fe9620586be3b..40c15e10c5a91 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -2015,8 +2015,6 @@ /************************************************************/ \ \ declare_constant(JVM_ACC_WRITTEN_FLAGS) \ - declare_constant(JVM_ACC_HAS_FINALIZER) \ - declare_constant(JVM_ACC_IS_CLONEABLE_FAST) \ \ declare_constant(JVM_CONSTANT_Utf8) \ declare_constant(JVM_CONSTANT_Unicode) \ diff --git a/src/hotspot/share/utilities/accessFlags.hpp b/src/hotspot/share/utilities/accessFlags.hpp index 78bf179e03afd..74ccbd20ac142 100644 --- a/src/hotspot/share/utilities/accessFlags.hpp +++ b/src/hotspot/share/utilities/accessFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,14 +40,7 @@ enum { // flags actually put in .class file JVM_ACC_WRITTEN_FLAGS = 0x00007FFF, - // HotSpot-specific access flags - // These Klass flags should be migrated, to a field such as InstanceKlass::_misc_flags, - // or to a similar flags field in Klass itself. // Do not add new ACC flags here. - JVM_ACC_HAS_FINALIZER = 0x40000000, // True if klass has a non-empty finalize() method - JVM_ACC_IS_CLONEABLE_FAST = (int)0x80000000,// True if klass implements the Cloneable interface and can be optimized in generated code - JVM_ACC_IS_HIDDEN_CLASS = 0x04000000, // True if klass is hidden - JVM_ACC_IS_VALUE_BASED_CLASS = 0x08000000, // True if klass is marked as a ValueBased class }; @@ -77,12 +70,6 @@ class AccessFlags { // Attribute flags bool is_synthetic () const { return (_flags & JVM_ACC_SYNTHETIC ) != 0; } - // Klass* flags - bool has_finalizer () const { return (_flags & JVM_ACC_HAS_FINALIZER ) != 0; } - bool is_cloneable_fast () const { return (_flags & JVM_ACC_IS_CLONEABLE_FAST ) != 0; } - bool is_hidden_class () const { return (_flags & JVM_ACC_IS_HIDDEN_CLASS ) != 0; } - bool is_value_based_class () const { return (_flags & JVM_ACC_IS_VALUE_BASED_CLASS ) != 0; } - // get .class file flags jint get_flags () const { return (_flags & JVM_ACC_WRITTEN_FLAGS); } @@ -102,13 +89,6 @@ class AccessFlags { // attribute flags void set_is_synthetic() { _flags |= JVM_ACC_SYNTHETIC; } - // Klass* flags - // These are set at classfile parsing time so do not require atomic access. - void set_has_finalizer() { _flags |= JVM_ACC_HAS_FINALIZER; } - void set_is_cloneable_fast() { _flags |= JVM_ACC_IS_CLONEABLE_FAST; } - void set_is_hidden_class() { _flags |= JVM_ACC_IS_HIDDEN_CLASS; } - void set_is_value_based_class() { _flags |= JVM_ACC_IS_VALUE_BASED_CLASS; } - public: // Conversion jshort as_short() const { return (jshort)_flags; } diff --git a/src/hotspot/share/utilities/dtrace_disabled.hpp b/src/hotspot/share/utilities/dtrace_disabled.hpp index b6ffb5936ea85..6cbd79326ac1f 100644 --- a/src/hotspot/share/utilities/dtrace_disabled.hpp +++ b/src/hotspot/share/utilities/dtrace_disabled.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, 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 @@ -783,6 +783,10 @@ #define HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY_ENABLED() 0 #define HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN(arg0) #define HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN_ENABLED() 0 +#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY(arg0, arg1) +#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY_ENABLED() 0 +#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN(arg0) +#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN_ENABLED() 0 #define HOTSPOT_JNI_GETSTRINGUTFREGION_ENTRY(arg0, arg1, arg2, arg3, arg4) #define HOTSPOT_JNI_GETSTRINGUTFREGION_ENTRY_ENABLED() 0 #define HOTSPOT_JNI_GETSTRINGUTFREGION_RETURN() diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index f730b37b8fffa..10405a0604887 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -288,7 +288,7 @@ void Exceptions::fthrow(JavaThread* thread, const char* file, int line, Symbol* // parameter controls a check for a specific character appearing in the "name", which is only // allowed for classfile versions <= 47. We pass `true` so that we allow such strings as this code // know nothing about the actual string content. - assert(UTF8::is_legal_utf8((const unsigned char*)msg, (int)strlen(msg), true), "must be"); + assert(UTF8::is_legal_utf8((const unsigned char*)msg, strlen(msg), true), "must be"); _throw_msg(thread, file, line, h_name, msg); } diff --git a/src/java.base/aix/native/libnio/MappedMemoryUtils.c b/src/java.base/aix/native/libnio/MappedMemoryUtils.c index 5d0216cc25102..e17ca2092afab 100644 --- a/src/java.base/aix/native/libnio/MappedMemoryUtils.c +++ b/src/java.base/aix/native/libnio/MappedMemoryUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,8 @@ static long calculate_number_of_pages_in_range(void* address, size_t len, size_t return numPages; } -JNIEXPORT jboolean JNICALL -Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, - jlong len, jlong numPages) +jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) { jboolean loaded = JNI_TRUE; int result = 0; @@ -93,8 +92,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, +void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, jlong len) { char *a = (char *)jlong_to_ptr(address); @@ -104,9 +102,8 @@ Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, } } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, - jlong len) +void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, + jlong len) { char *a = (char *)jlong_to_ptr(address); int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED); @@ -198,8 +195,7 @@ static int validate_msync_address(size_t address) return 0; } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, +void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, jlong address, jlong len) { void* a = (void *)jlong_to_ptr(address); @@ -218,3 +214,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed"); } } + +#define FD "Ljava/io/FileDescriptor;" + +static JNINativeMethod methods[] = { + {"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0}, + {"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0}, + {"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0}, + {"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0}, +}; + +JNIEXPORT void JNICALL +Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls) +{ + (*env)->RegisterNatives(env, cls, + methods, sizeof(methods)/sizeof(methods[0])); +} diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index e2ec0909f4500..f7fa0dbe96b5f 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -4647,7 +4647,7 @@ public String descriptorString() { return Wrapper.forPrimitiveType(this).basicTypeString(); if (isArray()) { - return "[" + componentType.descriptorString(); + return "[".concat(componentType.descriptorString()); } else if (isHidden()) { String name = getName(); int index = name.indexOf('/'); @@ -4660,11 +4660,7 @@ public String descriptorString() { .toString(); } else { String name = getName().replace('.', '/'); - return new StringBuilder(name.length() + 2) - .append('L') - .append(name) - .append(';') - .toString(); + return StringConcatHelper.concat("L", name, ";"); } } diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 5817c37d6f62b..99056c353eb5c 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -2450,7 +2450,8 @@ static NativeLibrary loadLibrary(Class fromClass, String name) { * @param javaName the native method's declared name */ static long findNative(ClassLoader loader, Class clazz, String entryName, String javaName) { - long addr = findNativeInternal(loader, entryName); + NativeLibraries nativeLibraries = nativeLibrariesFor(loader); + long addr = nativeLibraries.find(entryName); if (addr != 0 && loader != null) { Reflection.ensureNativeAccess(clazz, clazz, javaName, true); } @@ -2462,11 +2463,11 @@ static long findNative(ClassLoader loader, Class clazz, String entryName, Str * to avoid a restricted check, as that check has already been performed when * obtaining the lookup. */ - static long findNativeInternal(ClassLoader loader, String entryName) { + static NativeLibraries nativeLibrariesFor(ClassLoader loader) { if (loader == null) { - return BootLoader.getNativeLibraries().find(entryName); + return BootLoader.getNativeLibraries(); } else { - return loader.libraries.find(entryName); + return loader.libraries; } } diff --git a/src/java.base/share/classes/java/lang/StringCoding.java b/src/java.base/share/classes/java/lang/StringCoding.java index 293fbdb78dc85..c02af28c37d8b 100644 --- a/src/java.base/share/classes/java/lang/StringCoding.java +++ b/src/java.base/share/classes/java/lang/StringCoding.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +35,45 @@ class StringCoding { private StringCoding() { } + /** + * Count the number of leading non-zero ascii chars in the range. + */ + public static int countNonZeroAscii(String s) { + byte[] value = s.value(); + if (s.isLatin1()) { + return countNonZeroAsciiLatin1(value, 0, value.length); + } else { + return countNonZeroAsciiUTF16(value, 0, s.length()); + } + } + + /** + * Count the number of non-zero ascii chars in the range. + */ + public static int countNonZeroAsciiLatin1(byte[] ba, int off, int len) { + int limit = off + len; + for (int i = off; i < limit; i++) { + if (ba[i] <= 0) { + return i - off; + } + } + return len; + } + + /** + * Count the number of leading non-zero ascii chars in the range. + */ + public static int countNonZeroAsciiUTF16(byte[] ba, int off, int strlen) { + int limit = off + strlen; + for (int i = off; i < limit; i++) { + char c = StringUTF16.charAt(ba, i); + if (c == 0 || c > 0x7F) { + return i - off; + } + } + return strlen; + } + public static boolean hasNegatives(byte[] ba, int off, int len) { return countPositives(ba, off, len) != len; } diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index ae2b969340905..d0c558ed93a1a 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -783,4 +783,20 @@ static int checkOverflow(int value) { } throw new OutOfMemoryError("Overflow: String length out of range"); } + + @ForceInline + private static String concat0(String prefix, String str, String suffix) { + byte coder = (byte) (prefix.coder() | str.coder() | suffix.coder()); + int len = prefix.length() + str.length(); + byte[] buf = newArrayWithSuffix(suffix, len, coder); + prepend(len, coder, buf, str, prefix); + return new String(buf, coder); + } + + @ForceInline + static String concat(String prefix, Object value, String suffix) { + if (prefix == null) prefix = "null"; + if (suffix == null) suffix = "null"; + return concat0(prefix, stringOf(value), suffix); + } } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 503167bc2dd0d..368db1928f113 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -70,6 +70,7 @@ import java.util.stream.Stream; import jdk.internal.javac.Restricted; +import jdk.internal.loader.NativeLibraries; import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; import jdk.internal.misc.Blocker; import jdk.internal.misc.CarrierThreadLocal; @@ -2569,6 +2570,9 @@ public Stream layers(ClassLoader loader) { public int countPositives(byte[] bytes, int offset, int length) { return StringCoding.countPositives(bytes, offset, length); } + public int countNonZeroAscii(String s) { + return StringCoding.countNonZeroAscii(s); + } public String newStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException { return String.newStringNoRepl(bytes, cs); } @@ -2650,13 +2654,17 @@ public String join(String prefix, String suffix, String delimiter, String[] elem return String.join(prefix, suffix, delimiter, elements, size); } + public String concat(String prefix, Object value, String suffix) { + return StringConcatHelper.concat(prefix, value, suffix); + } + public Object classData(Class c) { return c.getClassData(); } @Override - public long findNative(ClassLoader loader, String entry) { - return ClassLoader.findNativeInternal(loader, entry); + public NativeLibraries nativeLibrariesFor(ClassLoader loader) { + return ClassLoader.nativeLibrariesFor(loader); } @Override diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index 75413011731e4..be0778d198458 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -262,7 +262,7 @@ default CodeBuilder ifThen(Consumer thenHandler) { */ default CodeBuilder ifThen(Opcode opcode, Consumer thenHandler) { - if (opcode.kind() != Opcode.Kind.BRANCH || opcode.primaryTypeKind() == TypeKind.VOID) { + if (opcode.kind() != Opcode.Kind.BRANCH || BytecodeHelpers.isUnconditionalBranch(opcode)) { throw new IllegalArgumentException("Illegal branch opcode: " + opcode); } @@ -312,7 +312,7 @@ default CodeBuilder ifThenElse(Consumer thenHandler, default CodeBuilder ifThenElse(Opcode opcode, Consumer thenHandler, Consumer elseHandler) { - if (opcode.kind() != Opcode.Kind.BRANCH || opcode.primaryTypeKind() == TypeKind.VOID) { + if (opcode.kind() != Opcode.Kind.BRANCH || BytecodeHelpers.isUnconditionalBranch(opcode)) { throw new IllegalArgumentException("Illegal branch opcode: " + opcode); } diff --git a/src/java.base/share/classes/java/lang/classfile/Opcode.java b/src/java.base/share/classes/java/lang/classfile/Opcode.java index 9e4c35276cfc8..ab991d983453d 100644 --- a/src/java.base/share/classes/java/lang/classfile/Opcode.java +++ b/src/java.base/share/classes/java/lang/classfile/Opcode.java @@ -24,8 +24,6 @@ */ package java.lang.classfile; -import java.lang.constant.ConstantDesc; -import java.lang.constant.ConstantDescs; import jdk.internal.javac.PreviewFeature; /** @@ -45,55 +43,55 @@ public enum Opcode { NOP(ClassFile.NOP, 1, Kind.NOP), /** Push null */ - ACONST_NULL(ClassFile.ACONST_NULL, 1, Kind.CONSTANT, TypeKind.REFERENCE, 0, ConstantDescs.NULL), + ACONST_NULL(ClassFile.ACONST_NULL, 1, Kind.CONSTANT), /** Push int constant -1 */ - ICONST_M1(ClassFile.ICONST_M1, 1, Kind.CONSTANT, TypeKind.INT, 0, -1), + ICONST_M1(ClassFile.ICONST_M1, 1, Kind.CONSTANT), /** Push int constant 0 */ - ICONST_0(ClassFile.ICONST_0, 1, Kind.CONSTANT, TypeKind.INT, 0, 0), + ICONST_0(ClassFile.ICONST_0, 1, Kind.CONSTANT), /** Push int constant 1 */ - ICONST_1(ClassFile.ICONST_1, 1, Kind.CONSTANT, TypeKind.INT, 0, 1), + ICONST_1(ClassFile.ICONST_1, 1, Kind.CONSTANT), /** Push int constant 2 */ - ICONST_2(ClassFile.ICONST_2, 1, Kind.CONSTANT, TypeKind.INT, 0, 2), + ICONST_2(ClassFile.ICONST_2, 1, Kind.CONSTANT), /** Push int constant 3 */ - ICONST_3(ClassFile.ICONST_3, 1, Kind.CONSTANT, TypeKind.INT, 0, 3), + ICONST_3(ClassFile.ICONST_3, 1, Kind.CONSTANT), /** Push int constant 4 */ - ICONST_4(ClassFile.ICONST_4, 1, Kind.CONSTANT, TypeKind.INT, 0, 4), + ICONST_4(ClassFile.ICONST_4, 1, Kind.CONSTANT), /** Push int constant 5 */ - ICONST_5(ClassFile.ICONST_5, 1, Kind.CONSTANT, TypeKind.INT, 0, 5), + ICONST_5(ClassFile.ICONST_5, 1, Kind.CONSTANT), /** Push long constant 0 */ - LCONST_0(ClassFile.LCONST_0, 1, Kind.CONSTANT, TypeKind.LONG, 0, 0L), + LCONST_0(ClassFile.LCONST_0, 1, Kind.CONSTANT), /** Push long constant 1 */ - LCONST_1(ClassFile.LCONST_1, 1, Kind.CONSTANT, TypeKind.LONG, 0, 1L), + LCONST_1(ClassFile.LCONST_1, 1, Kind.CONSTANT), /** Push float constant 0 */ - FCONST_0(ClassFile.FCONST_0, 1, Kind.CONSTANT, TypeKind.FLOAT, 0, 0.0f), + FCONST_0(ClassFile.FCONST_0, 1, Kind.CONSTANT), /** Push float constant 1 */ - FCONST_1(ClassFile.FCONST_1, 1, Kind.CONSTANT, TypeKind.FLOAT, 0, 1.0f), + FCONST_1(ClassFile.FCONST_1, 1, Kind.CONSTANT), /** Push float constant 2 */ - FCONST_2(ClassFile.FCONST_2, 1, Kind.CONSTANT, TypeKind.FLOAT, 0, 2.0f), + FCONST_2(ClassFile.FCONST_2, 1, Kind.CONSTANT), /** Push double constant 0 */ - DCONST_0(ClassFile.DCONST_0, 1, Kind.CONSTANT, TypeKind.DOUBLE, 0, 0.0d), + DCONST_0(ClassFile.DCONST_0, 1, Kind.CONSTANT), /** Push double constant 1 */ - DCONST_1(ClassFile.DCONST_1, 1, Kind.CONSTANT, TypeKind.DOUBLE, 0, 1.0d), + DCONST_1(ClassFile.DCONST_1, 1, Kind.CONSTANT), /** Push byte */ - BIPUSH(ClassFile.BIPUSH, 2, Kind.CONSTANT, TypeKind.BYTE), + BIPUSH(ClassFile.BIPUSH, 2, Kind.CONSTANT), /** Push short */ - SIPUSH(ClassFile.SIPUSH, 3, Kind.CONSTANT, TypeKind.SHORT), + SIPUSH(ClassFile.SIPUSH, 3, Kind.CONSTANT), /** Push item from run-time constant pool */ LDC(ClassFile.LDC, 2, Kind.CONSTANT), @@ -105,202 +103,202 @@ public enum Opcode { LDC2_W(ClassFile.LDC2_W, 3, Kind.CONSTANT), /** Load int from local variable */ - ILOAD(ClassFile.ILOAD, 2, Kind.LOAD, TypeKind.INT, -1), + ILOAD(ClassFile.ILOAD, 2, Kind.LOAD), /** Load long from local variable */ - LLOAD(ClassFile.LLOAD, 2, Kind.LOAD, TypeKind.LONG, -1), + LLOAD(ClassFile.LLOAD, 2, Kind.LOAD), /** Load float from local variable */ - FLOAD(ClassFile.FLOAD, 2, Kind.LOAD, TypeKind.FLOAT, -1), + FLOAD(ClassFile.FLOAD, 2, Kind.LOAD), /** Load double from local variable */ - DLOAD(ClassFile.DLOAD, 2, Kind.LOAD, TypeKind.DOUBLE, -1), + DLOAD(ClassFile.DLOAD, 2, Kind.LOAD), /** Load reference from local variable */ - ALOAD(ClassFile.ALOAD, 2, Kind.LOAD, TypeKind.REFERENCE, -1), + ALOAD(ClassFile.ALOAD, 2, Kind.LOAD), /** Load int from local variable 0 */ - ILOAD_0(ClassFile.ILOAD_0, 1, Kind.LOAD, TypeKind.INT, 0), + ILOAD_0(ClassFile.ILOAD_0, 1, Kind.LOAD), /** Load int from local variable 1 */ - ILOAD_1(ClassFile.ILOAD_1, 1, Kind.LOAD, TypeKind.INT, 1), + ILOAD_1(ClassFile.ILOAD_1, 1, Kind.LOAD), /** Load int from local variable 2 */ - ILOAD_2(ClassFile.ILOAD_2, 1, Kind.LOAD, TypeKind.INT, 2), + ILOAD_2(ClassFile.ILOAD_2, 1, Kind.LOAD), /** Load int from local variable3 */ - ILOAD_3(ClassFile.ILOAD_3, 1, Kind.LOAD, TypeKind.INT, 3), + ILOAD_3(ClassFile.ILOAD_3, 1, Kind.LOAD), /** Load long from local variable 0 */ - LLOAD_0(ClassFile.LLOAD_0, 1, Kind.LOAD, TypeKind.LONG, 0), + LLOAD_0(ClassFile.LLOAD_0, 1, Kind.LOAD), /** Load long from local variable 1 */ - LLOAD_1(ClassFile.LLOAD_1, 1, Kind.LOAD, TypeKind.LONG, 1), + LLOAD_1(ClassFile.LLOAD_1, 1, Kind.LOAD), /** Load long from local variable 2 */ - LLOAD_2(ClassFile.LLOAD_2, 1, Kind.LOAD, TypeKind.LONG, 2), + LLOAD_2(ClassFile.LLOAD_2, 1, Kind.LOAD), /** Load long from local variable 3 */ - LLOAD_3(ClassFile.LLOAD_3, 1, Kind.LOAD, TypeKind.LONG, 3), + LLOAD_3(ClassFile.LLOAD_3, 1, Kind.LOAD), /** Load float from local variable 0 */ - FLOAD_0(ClassFile.FLOAD_0, 1, Kind.LOAD, TypeKind.FLOAT, 0), + FLOAD_0(ClassFile.FLOAD_0, 1, Kind.LOAD), /** Load float from local variable 1 */ - FLOAD_1(ClassFile.FLOAD_1, 1, Kind.LOAD, TypeKind.FLOAT, 1), + FLOAD_1(ClassFile.FLOAD_1, 1, Kind.LOAD), /** Load float from local variable 2 */ - FLOAD_2(ClassFile.FLOAD_2, 1, Kind.LOAD, TypeKind.FLOAT, 2), + FLOAD_2(ClassFile.FLOAD_2, 1, Kind.LOAD), /** Load float from local variable 3 */ - FLOAD_3(ClassFile.FLOAD_3, 1, Kind.LOAD, TypeKind.FLOAT, 3), + FLOAD_3(ClassFile.FLOAD_3, 1, Kind.LOAD), /** Load double from local variable 0 */ - DLOAD_0(ClassFile.DLOAD_0, 1, Kind.LOAD, TypeKind.DOUBLE, 0), + DLOAD_0(ClassFile.DLOAD_0, 1, Kind.LOAD), /** Load double from local variable 1 */ - DLOAD_1(ClassFile.DLOAD_1, 1, Kind.LOAD, TypeKind.DOUBLE, 1), + DLOAD_1(ClassFile.DLOAD_1, 1, Kind.LOAD), /** Load double from local variable 2 */ - DLOAD_2(ClassFile.DLOAD_2, 1, Kind.LOAD, TypeKind.DOUBLE, 2), + DLOAD_2(ClassFile.DLOAD_2, 1, Kind.LOAD), /** Load double from local variable 3 */ - DLOAD_3(ClassFile.DLOAD_3, 1, Kind.LOAD, TypeKind.DOUBLE, 3), + DLOAD_3(ClassFile.DLOAD_3, 1, Kind.LOAD), /** Load reference from local variable 0 */ - ALOAD_0(ClassFile.ALOAD_0, 1, Kind.LOAD, TypeKind.REFERENCE, 0), + ALOAD_0(ClassFile.ALOAD_0, 1, Kind.LOAD), /** Load reference from local variable 1 */ - ALOAD_1(ClassFile.ALOAD_1, 1, Kind.LOAD, TypeKind.REFERENCE, 1), + ALOAD_1(ClassFile.ALOAD_1, 1, Kind.LOAD), /** Load reference from local variable 2 */ - ALOAD_2(ClassFile.ALOAD_2, 1, Kind.LOAD, TypeKind.REFERENCE, 2), + ALOAD_2(ClassFile.ALOAD_2, 1, Kind.LOAD), /** Load reference from local variable 3 */ - ALOAD_3(ClassFile.ALOAD_3, 1, Kind.LOAD, TypeKind.REFERENCE, 3), + ALOAD_3(ClassFile.ALOAD_3, 1, Kind.LOAD), /** Load int from array */ - IALOAD(ClassFile.IALOAD, 1, Kind.ARRAY_LOAD, TypeKind.INT), + IALOAD(ClassFile.IALOAD, 1, Kind.ARRAY_LOAD), /** Load long from array */ - LALOAD(ClassFile.LALOAD, 1, Kind.ARRAY_LOAD, TypeKind.LONG), + LALOAD(ClassFile.LALOAD, 1, Kind.ARRAY_LOAD), /** Load float from array */ - FALOAD(ClassFile.FALOAD, 1, Kind.ARRAY_LOAD, TypeKind.FLOAT), + FALOAD(ClassFile.FALOAD, 1, Kind.ARRAY_LOAD), /** Load double from array */ - DALOAD(ClassFile.DALOAD, 1, Kind.ARRAY_LOAD, TypeKind.DOUBLE), + DALOAD(ClassFile.DALOAD, 1, Kind.ARRAY_LOAD), /** Load reference from array */ - AALOAD(ClassFile.AALOAD, 1, Kind.ARRAY_LOAD, TypeKind.REFERENCE), + AALOAD(ClassFile.AALOAD, 1, Kind.ARRAY_LOAD), - /** Load byte or boolean from array */ - BALOAD(ClassFile.BALOAD, 1, Kind.ARRAY_LOAD, TypeKind.BYTE), + /** Load byte from array */ + BALOAD(ClassFile.BALOAD, 1, Kind.ARRAY_LOAD), /** Load char from array */ - CALOAD(ClassFile.CALOAD, 1, Kind.ARRAY_LOAD, TypeKind.CHAR), + CALOAD(ClassFile.CALOAD, 1, Kind.ARRAY_LOAD), /** Load short from array */ - SALOAD(ClassFile.SALOAD, 1, Kind.ARRAY_LOAD, TypeKind.SHORT), + SALOAD(ClassFile.SALOAD, 1, Kind.ARRAY_LOAD), /** Store int into local variable */ - ISTORE(ClassFile.ISTORE, 2, Kind.STORE, TypeKind.INT, -1), + ISTORE(ClassFile.ISTORE, 2, Kind.STORE), /** Store long into local variable */ - LSTORE(ClassFile.LSTORE, 2, Kind.STORE, TypeKind.LONG, -1), + LSTORE(ClassFile.LSTORE, 2, Kind.STORE), /** Store float into local variable */ - FSTORE(ClassFile.FSTORE, 2, Kind.STORE, TypeKind.FLOAT, -1), + FSTORE(ClassFile.FSTORE, 2, Kind.STORE), /** Store double into local variable */ - DSTORE(ClassFile.DSTORE, 2, Kind.STORE, TypeKind.DOUBLE, -1), + DSTORE(ClassFile.DSTORE, 2, Kind.STORE), /** Store reference into local variable */ - ASTORE(ClassFile.ASTORE, 2, Kind.STORE, TypeKind.REFERENCE, -1), + ASTORE(ClassFile.ASTORE, 2, Kind.STORE), /** Store int into local variable 0 */ - ISTORE_0(ClassFile.ISTORE_0, 1, Kind.STORE, TypeKind.INT, 0), + ISTORE_0(ClassFile.ISTORE_0, 1, Kind.STORE), /** Store int into local variable 1 */ - ISTORE_1(ClassFile.ISTORE_1, 1, Kind.STORE, TypeKind.INT, 1), + ISTORE_1(ClassFile.ISTORE_1, 1, Kind.STORE), /** Store int into local variable 2 */ - ISTORE_2(ClassFile.ISTORE_2, 1, Kind.STORE, TypeKind.INT, 2), + ISTORE_2(ClassFile.ISTORE_2, 1, Kind.STORE), /** Store int into local variable 3 */ - ISTORE_3(ClassFile.ISTORE_3, 1, Kind.STORE, TypeKind.INT, 3), + ISTORE_3(ClassFile.ISTORE_3, 1, Kind.STORE), /** Store long into local variable 0 */ - LSTORE_0(ClassFile.LSTORE_0, 1, Kind.STORE, TypeKind.LONG, 0), + LSTORE_0(ClassFile.LSTORE_0, 1, Kind.STORE), /** Store long into local variable 1 */ - LSTORE_1(ClassFile.LSTORE_1, 1, Kind.STORE, TypeKind.LONG, 1), + LSTORE_1(ClassFile.LSTORE_1, 1, Kind.STORE), /** Store long into local variable 2 */ - LSTORE_2(ClassFile.LSTORE_2, 1, Kind.STORE, TypeKind.LONG, 2), + LSTORE_2(ClassFile.LSTORE_2, 1, Kind.STORE), /** Store long into local variable 3 */ - LSTORE_3(ClassFile.LSTORE_3, 1, Kind.STORE, TypeKind.LONG, 3), + LSTORE_3(ClassFile.LSTORE_3, 1, Kind.STORE), /** Store float into local variable 0 */ - FSTORE_0(ClassFile.FSTORE_0, 1, Kind.STORE, TypeKind.FLOAT, 0), + FSTORE_0(ClassFile.FSTORE_0, 1, Kind.STORE), /** Store float into local variable 1 */ - FSTORE_1(ClassFile.FSTORE_1, 1, Kind.STORE, TypeKind.FLOAT, 1), + FSTORE_1(ClassFile.FSTORE_1, 1, Kind.STORE), /** Store float into local variable 2 */ - FSTORE_2(ClassFile.FSTORE_2, 1, Kind.STORE, TypeKind.FLOAT, 2), + FSTORE_2(ClassFile.FSTORE_2, 1, Kind.STORE), /** Store float into local variable 3 */ - FSTORE_3(ClassFile.FSTORE_3, 1, Kind.STORE, TypeKind.FLOAT, 3), + FSTORE_3(ClassFile.FSTORE_3, 1, Kind.STORE), /** Store double into local variable 0 */ - DSTORE_0(ClassFile.DSTORE_0, 1, Kind.STORE, TypeKind.DOUBLE, 0), + DSTORE_0(ClassFile.DSTORE_0, 1, Kind.STORE), /** Store double into local variable 1 */ - DSTORE_1(ClassFile.DSTORE_1, 1, Kind.STORE, TypeKind.DOUBLE, 1), + DSTORE_1(ClassFile.DSTORE_1, 1, Kind.STORE), /** Store double into local variable 2 */ - DSTORE_2(ClassFile.DSTORE_2, 1, Kind.STORE, TypeKind.DOUBLE, 2), + DSTORE_2(ClassFile.DSTORE_2, 1, Kind.STORE), /** Store double into local variable 3 */ - DSTORE_3(ClassFile.DSTORE_3, 1, Kind.STORE, TypeKind.DOUBLE, 3), + DSTORE_3(ClassFile.DSTORE_3, 1, Kind.STORE), /** Store reference into local variable 0 */ - ASTORE_0(ClassFile.ASTORE_0, 1, Kind.STORE, TypeKind.REFERENCE, 0), + ASTORE_0(ClassFile.ASTORE_0, 1, Kind.STORE), /** Store reference into local variable 1 */ - ASTORE_1(ClassFile.ASTORE_1, 1, Kind.STORE, TypeKind.REFERENCE, 1), + ASTORE_1(ClassFile.ASTORE_1, 1, Kind.STORE), /** Store reference into local variable 2 */ - ASTORE_2(ClassFile.ASTORE_2, 1, Kind.STORE, TypeKind.REFERENCE, 2), + ASTORE_2(ClassFile.ASTORE_2, 1, Kind.STORE), /** Store reference into local variable 3 */ - ASTORE_3(ClassFile.ASTORE_3, 1, Kind.STORE, TypeKind.REFERENCE, 3), + ASTORE_3(ClassFile.ASTORE_3, 1, Kind.STORE), /** Store into int array */ - IASTORE(ClassFile.IASTORE, 1, Kind.ARRAY_STORE, TypeKind.INT), + IASTORE(ClassFile.IASTORE, 1, Kind.ARRAY_STORE), /** Store into long array */ - LASTORE(ClassFile.LASTORE, 1, Kind.ARRAY_STORE, TypeKind.LONG), + LASTORE(ClassFile.LASTORE, 1, Kind.ARRAY_STORE), /** Store into float array */ - FASTORE(ClassFile.FASTORE, 1, Kind.ARRAY_STORE, TypeKind.FLOAT), + FASTORE(ClassFile.FASTORE, 1, Kind.ARRAY_STORE), /** Store into double array */ - DASTORE(ClassFile.DASTORE, 1, Kind.ARRAY_STORE, TypeKind.DOUBLE), + DASTORE(ClassFile.DASTORE, 1, Kind.ARRAY_STORE), /** Store into reference array */ - AASTORE(ClassFile.AASTORE, 1, Kind.ARRAY_STORE, TypeKind.REFERENCE), + AASTORE(ClassFile.AASTORE, 1, Kind.ARRAY_STORE), - /** Store into byte or boolean array */ - BASTORE(ClassFile.BASTORE, 1, Kind.ARRAY_STORE, TypeKind.BYTE), + /** Store into byte array */ + BASTORE(ClassFile.BASTORE, 1, Kind.ARRAY_STORE), /** Store into char array */ - CASTORE(ClassFile.CASTORE, 1, Kind.ARRAY_STORE, TypeKind.CHAR), + CASTORE(ClassFile.CASTORE, 1, Kind.ARRAY_STORE), /** Store into short array */ - SASTORE(ClassFile.SASTORE, 1, Kind.ARRAY_STORE, TypeKind.SHORT), + SASTORE(ClassFile.SASTORE, 1, Kind.ARRAY_STORE), /** Pop the top operand stack value */ POP(ClassFile.POP, 1, Kind.STACK), @@ -330,220 +328,220 @@ public enum Opcode { SWAP(ClassFile.SWAP, 1, Kind.STACK), /** Add int */ - IADD(ClassFile.IADD, 1, Kind.OPERATOR, TypeKind.INT), + IADD(ClassFile.IADD, 1, Kind.OPERATOR), /** Add long */ - LADD(ClassFile.LADD, 1, Kind.OPERATOR, TypeKind.LONG), + LADD(ClassFile.LADD, 1, Kind.OPERATOR), /** Add float */ - FADD(ClassFile.FADD, 1, Kind.OPERATOR, TypeKind.FLOAT), + FADD(ClassFile.FADD, 1, Kind.OPERATOR), /** Add double */ - DADD(ClassFile.DADD, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DADD(ClassFile.DADD, 1, Kind.OPERATOR), /** Subtract int */ - ISUB(ClassFile.ISUB, 1, Kind.OPERATOR, TypeKind.INT), + ISUB(ClassFile.ISUB, 1, Kind.OPERATOR), /** Subtract long */ - LSUB(ClassFile.LSUB, 1, Kind.OPERATOR, TypeKind.LONG), + LSUB(ClassFile.LSUB, 1, Kind.OPERATOR), /** Subtract float */ - FSUB(ClassFile.FSUB, 1, Kind.OPERATOR, TypeKind.FLOAT), + FSUB(ClassFile.FSUB, 1, Kind.OPERATOR), /** Subtract double */ - DSUB(ClassFile.DSUB, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DSUB(ClassFile.DSUB, 1, Kind.OPERATOR), /** Multiply int */ - IMUL(ClassFile.IMUL, 1, Kind.OPERATOR, TypeKind.INT), + IMUL(ClassFile.IMUL, 1, Kind.OPERATOR), /** Multiply long */ - LMUL(ClassFile.LMUL, 1, Kind.OPERATOR, TypeKind.LONG), + LMUL(ClassFile.LMUL, 1, Kind.OPERATOR), /** Multiply float */ - FMUL(ClassFile.FMUL, 1, Kind.OPERATOR, TypeKind.FLOAT), + FMUL(ClassFile.FMUL, 1, Kind.OPERATOR), /** Multiply double */ - DMUL(ClassFile.DMUL, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DMUL(ClassFile.DMUL, 1, Kind.OPERATOR), /** Divide int */ - IDIV(ClassFile.IDIV, 1, Kind.OPERATOR, TypeKind.INT), + IDIV(ClassFile.IDIV, 1, Kind.OPERATOR), /** Divide long */ - LDIV(ClassFile.LDIV, 1, Kind.OPERATOR, TypeKind.LONG), + LDIV(ClassFile.LDIV, 1, Kind.OPERATOR), /** Divide float */ - FDIV(ClassFile.FDIV, 1, Kind.OPERATOR, TypeKind.FLOAT), + FDIV(ClassFile.FDIV, 1, Kind.OPERATOR), /** Divide double */ - DDIV(ClassFile.DDIV, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DDIV(ClassFile.DDIV, 1, Kind.OPERATOR), /** Remainder int */ - IREM(ClassFile.IREM, 1, Kind.OPERATOR, TypeKind.INT), + IREM(ClassFile.IREM, 1, Kind.OPERATOR), /** Remainder long */ - LREM(ClassFile.LREM, 1, Kind.OPERATOR, TypeKind.LONG), + LREM(ClassFile.LREM, 1, Kind.OPERATOR), /** Remainder float */ - FREM(ClassFile.FREM, 1, Kind.OPERATOR, TypeKind.FLOAT), + FREM(ClassFile.FREM, 1, Kind.OPERATOR), /** Remainder double */ - DREM(ClassFile.DREM, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DREM(ClassFile.DREM, 1, Kind.OPERATOR), /** Negate int */ - INEG(ClassFile.INEG, 1, Kind.OPERATOR, TypeKind.INT), + INEG(ClassFile.INEG, 1, Kind.OPERATOR), /** Negate long */ - LNEG(ClassFile.LNEG, 1, Kind.OPERATOR, TypeKind.LONG), + LNEG(ClassFile.LNEG, 1, Kind.OPERATOR), /** Negate float */ - FNEG(ClassFile.FNEG, 1, Kind.OPERATOR, TypeKind.FLOAT), + FNEG(ClassFile.FNEG, 1, Kind.OPERATOR), /** Negate double */ - DNEG(ClassFile.DNEG, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DNEG(ClassFile.DNEG, 1, Kind.OPERATOR), /** Shift left int */ - ISHL(ClassFile.ISHL, 1, Kind.OPERATOR, TypeKind.INT), + ISHL(ClassFile.ISHL, 1, Kind.OPERATOR), /** Shift left long */ - LSHL(ClassFile.LSHL, 1, Kind.OPERATOR, TypeKind.LONG), + LSHL(ClassFile.LSHL, 1, Kind.OPERATOR), /** Shift right int */ - ISHR(ClassFile.ISHR, 1, Kind.OPERATOR, TypeKind.INT), + ISHR(ClassFile.ISHR, 1, Kind.OPERATOR), /** Shift right long */ - LSHR(ClassFile.LSHR, 1, Kind.OPERATOR, TypeKind.LONG), + LSHR(ClassFile.LSHR, 1, Kind.OPERATOR), /** Logical shift right int */ - IUSHR(ClassFile.IUSHR, 1, Kind.OPERATOR, TypeKind.INT), + IUSHR(ClassFile.IUSHR, 1, Kind.OPERATOR), /** Logical shift right long */ - LUSHR(ClassFile.LUSHR, 1, Kind.OPERATOR, TypeKind.LONG), + LUSHR(ClassFile.LUSHR, 1, Kind.OPERATOR), /** Boolean AND int */ - IAND(ClassFile.IAND, 1, Kind.OPERATOR, TypeKind.INT), + IAND(ClassFile.IAND, 1, Kind.OPERATOR), /** Boolean AND long */ - LAND(ClassFile.LAND, 1, Kind.OPERATOR, TypeKind.LONG), + LAND(ClassFile.LAND, 1, Kind.OPERATOR), /** Boolean OR int */ - IOR(ClassFile.IOR, 1, Kind.OPERATOR, TypeKind.INT), + IOR(ClassFile.IOR, 1, Kind.OPERATOR), /** Boolean OR long */ - LOR(ClassFile.LOR, 1, Kind.OPERATOR, TypeKind.LONG), + LOR(ClassFile.LOR, 1, Kind.OPERATOR), /** Boolean XOR int */ - IXOR(ClassFile.IXOR, 1, Kind.OPERATOR, TypeKind.INT), + IXOR(ClassFile.IXOR, 1, Kind.OPERATOR), /** Boolean XOR long */ - LXOR(ClassFile.LXOR, 1, Kind.OPERATOR, TypeKind.LONG), + LXOR(ClassFile.LXOR, 1, Kind.OPERATOR), /** Increment local variable by constant */ - IINC(ClassFile.IINC, 3, Kind.INCREMENT, TypeKind.INT, -1), + IINC(ClassFile.IINC, 3, Kind.INCREMENT), /** Convert int to long */ - I2L(ClassFile.I2L, 1, Kind.CONVERT, TypeKind.INT, TypeKind.LONG), + I2L(ClassFile.I2L, 1, Kind.CONVERT), /** Convert int to float */ - I2F(ClassFile.I2F, 1, Kind.CONVERT, TypeKind.INT, TypeKind.FLOAT), + I2F(ClassFile.I2F, 1, Kind.CONVERT), /** Convert int to double */ - I2D(ClassFile.I2D, 1, Kind.CONVERT, TypeKind.INT, TypeKind.DOUBLE), + I2D(ClassFile.I2D, 1, Kind.CONVERT), /** Convert long to int */ - L2I(ClassFile.L2I, 1, Kind.CONVERT, TypeKind.LONG, TypeKind.INT), + L2I(ClassFile.L2I, 1, Kind.CONVERT), /** Convert long to float */ - L2F(ClassFile.L2F, 1, Kind.CONVERT, TypeKind.LONG, TypeKind.FLOAT), + L2F(ClassFile.L2F, 1, Kind.CONVERT), /** Convert long to double */ - L2D(ClassFile.L2D, 1, Kind.CONVERT, TypeKind.LONG, TypeKind.DOUBLE), + L2D(ClassFile.L2D, 1, Kind.CONVERT), /** Convert float to int */ - F2I(ClassFile.F2I, 1, Kind.CONVERT, TypeKind.FLOAT, TypeKind.INT), + F2I(ClassFile.F2I, 1, Kind.CONVERT), /** Convert float to long */ - F2L(ClassFile.F2L, 1, Kind.CONVERT, TypeKind.FLOAT, TypeKind.LONG), + F2L(ClassFile.F2L, 1, Kind.CONVERT), /** Convert float to double */ - F2D(ClassFile.F2D, 1, Kind.CONVERT, TypeKind.FLOAT, TypeKind.DOUBLE), + F2D(ClassFile.F2D, 1, Kind.CONVERT), /** Convert double to int */ - D2I(ClassFile.D2I, 1, Kind.CONVERT, TypeKind.DOUBLE, TypeKind.INT), + D2I(ClassFile.D2I, 1, Kind.CONVERT), /** Convert double to long */ - D2L(ClassFile.D2L, 1, Kind.CONVERT, TypeKind.DOUBLE, TypeKind.LONG), + D2L(ClassFile.D2L, 1, Kind.CONVERT), /** Convert double to float */ - D2F(ClassFile.D2F, 1, Kind.CONVERT, TypeKind.DOUBLE, TypeKind.FLOAT), + D2F(ClassFile.D2F, 1, Kind.CONVERT), /** Convert int to byte */ - I2B(ClassFile.I2B, 1, Kind.CONVERT, TypeKind.INT, TypeKind.BYTE), + I2B(ClassFile.I2B, 1, Kind.CONVERT), /** Convert int to char */ - I2C(ClassFile.I2C, 1, Kind.CONVERT, TypeKind.INT, TypeKind.CHAR), + I2C(ClassFile.I2C, 1, Kind.CONVERT), /** Convert int to short */ - I2S(ClassFile.I2S, 1, Kind.CONVERT, TypeKind.INT, TypeKind.SHORT), + I2S(ClassFile.I2S, 1, Kind.CONVERT), /** Compare long */ - LCMP(ClassFile.LCMP, 1, Kind.OPERATOR, TypeKind.LONG), + LCMP(ClassFile.LCMP, 1, Kind.OPERATOR), /** Compare float */ - FCMPL(ClassFile.FCMPL, 1, Kind.OPERATOR, TypeKind.FLOAT), + FCMPL(ClassFile.FCMPL, 1, Kind.OPERATOR), /** Compare float */ - FCMPG(ClassFile.FCMPG, 1, Kind.OPERATOR, TypeKind.FLOAT), + FCMPG(ClassFile.FCMPG, 1, Kind.OPERATOR), /** Compare double */ - DCMPL(ClassFile.DCMPL, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DCMPL(ClassFile.DCMPL, 1, Kind.OPERATOR), /** Compare double */ - DCMPG(ClassFile.DCMPG, 1, Kind.OPERATOR, TypeKind.DOUBLE), + DCMPG(ClassFile.DCMPG, 1, Kind.OPERATOR), /** Branch if int comparison with zero succeeds */ - IFEQ(ClassFile.IFEQ, 3, Kind.BRANCH, TypeKind.INT), + IFEQ(ClassFile.IFEQ, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFNE(ClassFile.IFNE, 3, Kind.BRANCH, TypeKind.INT), + IFNE(ClassFile.IFNE, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFLT(ClassFile.IFLT, 3, Kind.BRANCH, TypeKind.INT), + IFLT(ClassFile.IFLT, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFGE(ClassFile.IFGE, 3, Kind.BRANCH, TypeKind.INT), + IFGE(ClassFile.IFGE, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFGT(ClassFile.IFGT, 3, Kind.BRANCH, TypeKind.INT), + IFGT(ClassFile.IFGT, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFLE(ClassFile.IFLE, 3, Kind.BRANCH, TypeKind.INT), + IFLE(ClassFile.IFLE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPEQ(ClassFile.IF_ICMPEQ, 3, Kind.BRANCH, TypeKind.INT), + IF_ICMPEQ(ClassFile.IF_ICMPEQ, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPNE(ClassFile.IF_ICMPNE, 3, Kind.BRANCH, TypeKind.INT), + IF_ICMPNE(ClassFile.IF_ICMPNE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPLT(ClassFile.IF_ICMPLT, 3, Kind.BRANCH, TypeKind.INT), + IF_ICMPLT(ClassFile.IF_ICMPLT, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPGE(ClassFile.IF_ICMPGE, 3, Kind.BRANCH, TypeKind.INT), + IF_ICMPGE(ClassFile.IF_ICMPGE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPGT(ClassFile.IF_ICMPGT, 3, Kind.BRANCH, TypeKind.INT), + IF_ICMPGT(ClassFile.IF_ICMPGT, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPLE(ClassFile.IF_ICMPLE, 3, Kind.BRANCH, TypeKind.INT), + IF_ICMPLE(ClassFile.IF_ICMPLE, 3, Kind.BRANCH), /** Branch if reference comparison succeeds */ - IF_ACMPEQ(ClassFile.IF_ACMPEQ, 3, Kind.BRANCH, TypeKind.REFERENCE), + IF_ACMPEQ(ClassFile.IF_ACMPEQ, 3, Kind.BRANCH), /** Branch if reference comparison succeeds */ - IF_ACMPNE(ClassFile.IF_ACMPNE, 3, Kind.BRANCH, TypeKind.REFERENCE), + IF_ACMPNE(ClassFile.IF_ACMPNE, 3, Kind.BRANCH), /** Branch always */ - GOTO(ClassFile.GOTO, 3, Kind.BRANCH, TypeKind.VOID), + GOTO(ClassFile.GOTO, 3, Kind.BRANCH), /** * Jump subroutine is discontinued opcode @@ -564,22 +562,22 @@ public enum Opcode { LOOKUPSWITCH(ClassFile.LOOKUPSWITCH, -1, Kind.LOOKUP_SWITCH), /** Return int from method */ - IRETURN(ClassFile.IRETURN, 1, Kind.RETURN, TypeKind.INT), + IRETURN(ClassFile.IRETURN, 1, Kind.RETURN), /** Return long from method */ - LRETURN(ClassFile.LRETURN, 1, Kind.RETURN, TypeKind.LONG), + LRETURN(ClassFile.LRETURN, 1, Kind.RETURN), /** Return float from method */ - FRETURN(ClassFile.FRETURN, 1, Kind.RETURN, TypeKind.FLOAT), + FRETURN(ClassFile.FRETURN, 1, Kind.RETURN), /** Return double from method */ - DRETURN(ClassFile.DRETURN, 1, Kind.RETURN, TypeKind.DOUBLE), + DRETURN(ClassFile.DRETURN, 1, Kind.RETURN), /** Return reference from method */ - ARETURN(ClassFile.ARETURN, 1, Kind.RETURN, TypeKind.REFERENCE), + ARETURN(ClassFile.ARETURN, 1, Kind.RETURN), /** Return void from method */ - RETURN(ClassFile.RETURN, 1, Kind.RETURN, TypeKind.VOID), + RETURN(ClassFile.RETURN, 1, Kind.RETURN), /** Get static field from class */ GETSTATIC(ClassFile.GETSTATIC, 3, Kind.FIELD_ACCESS), @@ -621,7 +619,7 @@ public enum Opcode { ANEWARRAY(ClassFile.ANEWARRAY, 3, Kind.NEW_REF_ARRAY), /** Get length of array */ - ARRAYLENGTH(ClassFile.ARRAYLENGTH, 1, Kind.OPERATOR, TypeKind.INT), + ARRAYLENGTH(ClassFile.ARRAYLENGTH, 1, Kind.OPERATOR), /** Throw exception or error */ ATHROW(ClassFile.ATHROW, 1, Kind.THROW_EXCEPTION), @@ -642,13 +640,13 @@ public enum Opcode { MULTIANEWARRAY(ClassFile.MULTIANEWARRAY, 4, Kind.NEW_MULTI_ARRAY), /** Branch if reference is null */ - IFNULL(ClassFile.IFNULL, 3, Kind.BRANCH, TypeKind.REFERENCE), + IFNULL(ClassFile.IFNULL, 3, Kind.BRANCH), /** Branch if reference not null */ - IFNONNULL(ClassFile.IFNONNULL, 3, Kind.BRANCH, TypeKind.REFERENCE), + IFNONNULL(ClassFile.IFNONNULL, 3, Kind.BRANCH), /** Branch always (wide index) */ - GOTO_W(ClassFile.GOTO_W, 5, Kind.BRANCH, TypeKind.VOID), + GOTO_W(ClassFile.GOTO_W, 5, Kind.BRANCH), /** * Jump subroutine (wide index) is discontinued opcode @@ -657,34 +655,34 @@ public enum Opcode { JSR_W(ClassFile.JSR_W, 5, Kind.DISCONTINUED_JSR), /** Load int from local variable (wide index) */ - ILOAD_W((ClassFile.WIDE << 8) | ClassFile.ILOAD, 4, Kind.LOAD, TypeKind.INT, -1), + ILOAD_W((ClassFile.WIDE << 8) | ClassFile.ILOAD, 4, Kind.LOAD), /** Load long from local variable (wide index) */ - LLOAD_W((ClassFile.WIDE << 8) | ClassFile.LLOAD, 4, Kind.LOAD, TypeKind.LONG, -1), + LLOAD_W((ClassFile.WIDE << 8) | ClassFile.LLOAD, 4, Kind.LOAD), /** Load float from local variable (wide index) */ - FLOAD_W((ClassFile.WIDE << 8) | ClassFile.FLOAD, 4, Kind.LOAD, TypeKind.FLOAT, -1), + FLOAD_W((ClassFile.WIDE << 8) | ClassFile.FLOAD, 4, Kind.LOAD), /** Load double from local variable (wide index) */ - DLOAD_W((ClassFile.WIDE << 8) | ClassFile.DLOAD, 4, Kind.LOAD, TypeKind.DOUBLE, -1), + DLOAD_W((ClassFile.WIDE << 8) | ClassFile.DLOAD, 4, Kind.LOAD), /** Load reference from local variable (wide index) */ - ALOAD_W((ClassFile.WIDE << 8) | ClassFile.ALOAD, 4, Kind.LOAD, TypeKind.REFERENCE, -1), + ALOAD_W((ClassFile.WIDE << 8) | ClassFile.ALOAD, 4, Kind.LOAD), /** Store int into local variable (wide index) */ - ISTORE_W((ClassFile.WIDE << 8) | ClassFile.ISTORE, 4, Kind.STORE, TypeKind.INT, -1), + ISTORE_W((ClassFile.WIDE << 8) | ClassFile.ISTORE, 4, Kind.STORE), /** Store long into local variable (wide index) */ - LSTORE_W((ClassFile.WIDE << 8) | ClassFile.LSTORE, 4, Kind.STORE, TypeKind.LONG, -1), + LSTORE_W((ClassFile.WIDE << 8) | ClassFile.LSTORE, 4, Kind.STORE), /** Store float into local variable (wide index) */ - FSTORE_W((ClassFile.WIDE << 8) | ClassFile.FSTORE, 4, Kind.STORE, TypeKind.FLOAT, -1), + FSTORE_W((ClassFile.WIDE << 8) | ClassFile.FSTORE, 4, Kind.STORE), /** Store double into local variable (wide index) */ - DSTORE_W((ClassFile.WIDE << 8) | ClassFile.DSTORE, 4, Kind.STORE, TypeKind.DOUBLE, -1), + DSTORE_W((ClassFile.WIDE << 8) | ClassFile.DSTORE, 4, Kind.STORE), /** Store reference into local variable (wide index) */ - ASTORE_W((ClassFile.WIDE << 8) | ClassFile.ASTORE, 4, Kind.STORE, TypeKind.REFERENCE, -1), + ASTORE_W((ClassFile.WIDE << 8) | ClassFile.ASTORE, 4, Kind.STORE), /** * Return from subroutine (wide index) is discontinued opcode @@ -693,7 +691,7 @@ public enum Opcode { RET_W((ClassFile.WIDE << 8) | ClassFile.RET, 4, Kind.DISCONTINUED_RET), /** Increment local variable by constant (wide index) */ - IINC_W((ClassFile.WIDE << 8) | ClassFile.IINC, 6, Kind.INCREMENT, TypeKind.INT, -1); + IINC_W((ClassFile.WIDE << 8) | ClassFile.IINC, 6, Kind.INCREMENT); /** * Kinds of opcodes. @@ -1078,59 +1076,41 @@ public static enum Kind { private final int bytecode; private final int sizeIfFixed; private final Kind kind; - private final TypeKind primaryTypeKind; - private final TypeKind secondaryTypeKind; - private final int slot; - private final ConstantDesc constantValue; Opcode(int bytecode, int sizeIfFixed, Kind kind) { - this(bytecode, sizeIfFixed, kind, null, null, -1, null); - } - - Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind typeKind) { - this(bytecode, sizeIfFixed, kind, typeKind, null, -1, null); - } - - Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind typeKind, int slot) { - this(bytecode, sizeIfFixed, kind, typeKind, null, slot, null); - } - - Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind typeKind, int slot, ConstantDesc constantValue) { - this(bytecode, sizeIfFixed, kind, typeKind, null, slot, constantValue); - } - - Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind primaryTypeKind, TypeKind secondaryTypeKind) { - this(bytecode, sizeIfFixed, kind, primaryTypeKind, secondaryTypeKind, 0, null); - } - - Opcode(int bytecode, - int sizeIfFixed, - Kind kind, - TypeKind primaryTypeKind, - TypeKind secondaryTypeKind, - int slot, - ConstantDesc constantValue) { this.bytecode = bytecode; this.sizeIfFixed = sizeIfFixed; this.kind = kind; - this.primaryTypeKind = primaryTypeKind; - this.secondaryTypeKind = secondaryTypeKind; - this.slot = slot; - this.constantValue = constantValue; } /** - * {@return bytecode} + * {@return the opcode value} For {@linkplain #isWide() wide} pseudo-opcodes, returns the + * first 2 bytes of the instruction, which are the {@code wide} opcode and the functional + * local variable opcode, as a U2 value. */ public int bytecode() { return bytecode; } /** - * {@return true if the instruction has extended local variable index by additional bytes} + * {@return true if this is a pseudo-opcode modified by {@code wide}} + * + * @see #ILOAD_W + * @see #LLOAD_W + * @see #FLOAD_W + * @see #DLOAD_W + * @see #ALOAD_W + * @see #ISTORE_W + * @see #LSTORE_W + * @see #FSTORE_W + * @see #DSTORE_W + * @see #ASTORE_W + * @see #RET_W + * @see #IINC_W */ public boolean isWide() { return bytecode > 255; } /** - * {@return size of the instruction if fixed, or -1 otherwise} + * {@return size of the instruction in bytes if fixed, or -1 otherwise} This size includes + * the opcode itself. */ public int sizeIfFixed() { return sizeIfFixed; } @@ -1138,42 +1118,4 @@ public static enum Kind { * {@return instruction kind} */ public Kind kind() { return kind; } - - /** - * {@return primary type kind for instructions operating with at least one type, or null otherwise} - */ - public TypeKind primaryTypeKind() { - return primaryTypeKind; - } - - /** - * {@return secondary type kind for instructions operating with two types, or null otherwise} - */ - public TypeKind secondaryTypeKind() { - return secondaryTypeKind; - } - - /** - * {@return local variable slot for instructions operating with local variable, or -1 otherwise} - */ - public int slot() { - return slot; - } - - /** - * {@return constant value for constant instructions, or null otherwise} - */ - public ConstantDesc constantValue() { - return constantValue; - } - - /** - * {@return true if the instruction represents an unconditional branch} - */ - public boolean isUnconditionalBranch() { - return switch (this) { - case GOTO, ATHROW, GOTO_W, LOOKUPSWITCH, TABLESWITCH -> true; - default -> kind() == Kind.RETURN; - }; - } } diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java index 022c45fdeef4d..6f07805a1e81c 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/ConstantInstruction.java @@ -75,7 +75,7 @@ sealed interface IntrinsicConstantInstruction extends ConstantInstruction */ @Override default TypeKind typeKind() { - return opcode().primaryTypeKind(); + return BytecodeHelpers.intrinsicConstantType(opcode()); } } @@ -98,7 +98,7 @@ sealed interface ArgumentConstantInstruction extends ConstantInstruction */ @Override default TypeKind typeKind() { - return opcode().primaryTypeKind(); + return TypeKind.INT; } } @@ -137,7 +137,7 @@ default TypeKind typeKind() { */ static IntrinsicConstantInstruction ofIntrinsic(Opcode op) { Util.checkKind(op, Opcode.Kind.CONSTANT); - if (op.constantValue() == null) + if (op.sizeIfFixed() != 1) throw new IllegalArgumentException(String.format("Wrong opcode specified; found %s, expected xCONST_val", op)); return new AbstractInstruction.UnboundIntrinsicConstantInstruction(op); } diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index 0c714850a8fa3..b93d95223529e 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -36,6 +36,7 @@ import static jdk.internal.constant.ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS; import static jdk.internal.constant.ConstantUtils.arrayDepth; import static jdk.internal.constant.ConstantUtils.binaryToInternal; +import static jdk.internal.constant.ConstantUtils.concat; import static jdk.internal.constant.ConstantUtils.forPrimitiveType; import static jdk.internal.constant.ConstantUtils.internalToBinary; import static jdk.internal.constant.ConstantUtils.validateBinaryClassName; @@ -83,7 +84,7 @@ public sealed interface ClassDesc */ static ClassDesc of(String name) { validateBinaryClassName(name); - return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";"); + return ClassDesc.ofDescriptor(concat("L", binaryToInternal(name), ";")); } /** @@ -109,7 +110,7 @@ static ClassDesc of(String name) { */ static ClassDesc ofInternalName(String name) { validateInternalClassName(name); - return ClassDesc.ofDescriptor("L" + name + ";"); + return ClassDesc.ofDescriptor(concat("L", name, ";")); } /** @@ -132,8 +133,8 @@ static ClassDesc of(String packageName, String className) { return of(className); } validateMemberName(className, false); - return ofDescriptor("L" + binaryToInternal(packageName) + - "/" + className + ";"); + return ofDescriptor('L' + binaryToInternal(packageName) + + '/' + className + ';'); } /** @@ -361,7 +362,7 @@ else if (isArray()) { ClassDesc c = this; for (int i=0; i c) { + checkForComodification(); + root.sortRange(c, offset, offset + size); + updateSizeAndModCount(0); + } } /** @@ -1799,10 +1806,14 @@ private void replaceAllRange(UnaryOperator operator, int i, int end) { } @Override - @SuppressWarnings("unchecked") public void sort(Comparator c) { + sortRange(c, 0, size); + } + + @SuppressWarnings("unchecked") + private void sortRange(Comparator c, int fromIndex, int toIndex) { final int expectedModCount = modCount; - Arrays.sort((E[]) elementData, 0, size, c); + Arrays.sort((E[]) elementData, fromIndex, toIndex, c); if (modCount != expectedModCount) throw new ConcurrentModificationException(); modCount++; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 2a89386f742dc..98238af383174 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -29,6 +29,7 @@ import java.io.PrintStream; import java.lang.annotation.Annotation; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.lang.module.ModuleDescriptor; @@ -46,6 +47,7 @@ import java.util.concurrent.RejectedExecutionException; import java.util.stream.Stream; +import jdk.internal.loader.NativeLibraries; import jdk.internal.misc.CarrierThreadLocal; import jdk.internal.module.ServicesCatalog; import jdk.internal.reflect.ConstantPool; @@ -318,6 +320,11 @@ public interface JavaLangAccess { */ int countPositives(byte[] ba, int off, int len); + /** + * Count the number of leading non-zero ascii chars in the String. + */ + int countNonZeroAscii(String s); + /** * Constructs a new {@code String} by decoding the specified subarray of * bytes using the specified {@linkplain java.nio.charset.Charset charset}. @@ -457,6 +464,11 @@ public interface JavaLangAccess { */ String join(String prefix, String suffix, String delimiter, String[] elements, int size); + /** + * Concatenation of prefix and suffix characters to a String for early bootstrap + */ + String concat(String prefix, Object value, String suffix); + /* * Get the class data associated with the given class. * @param c the class @@ -468,7 +480,11 @@ public interface JavaLangAccess { int getCharsUTF16(long i, int index, byte[] buf); - long findNative(ClassLoader loader, String entry); + /** + * Returns the {@link NativeLibraries} object associated with the provided class loader. + * This is used by {@link SymbolLookup#loaderLookup()}. + */ + NativeLibraries nativeLibrariesFor(ClassLoader loader); /** * Direct access to Shutdown.exit to avoid security manager checks diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 463668dcb0079..10c9cf0a5e15b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -145,7 +145,7 @@ public BoundLoadInstruction(Opcode op, CodeImpl code, int pos) { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.loadType(op); } @Override @@ -173,7 +173,7 @@ public BoundStoreInstruction(Opcode op, CodeImpl code, int pos) { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.storeType(op); } @Override @@ -800,7 +800,7 @@ public int slot() { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.loadType(op); } @Override @@ -831,7 +831,7 @@ public int slot() { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.storeType(op); } @Override @@ -993,7 +993,7 @@ public UnboundReturnInstruction(Opcode op) { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.returnType(op); } @Override @@ -1226,7 +1226,7 @@ public UnboundArrayLoadInstruction(Opcode op) { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.arrayLoadType(op); } } @@ -1239,7 +1239,7 @@ public UnboundArrayStoreInstruction(Opcode op) { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.arrayStoreType(op); } } @@ -1286,12 +1286,12 @@ public UnboundConvertInstruction(Opcode op) { @Override public TypeKind fromType() { - return op.primaryTypeKind(); + return BytecodeHelpers.convertFromType(op); } @Override public TypeKind toType() { - return op.secondaryTypeKind(); + return BytecodeHelpers.convertToType(op); } } @@ -1304,22 +1304,19 @@ public UnboundOperatorInstruction(Opcode op) { @Override public TypeKind typeKind() { - return op.primaryTypeKind(); + return BytecodeHelpers.operatorOperandType(op); } } public static final class UnboundIntrinsicConstantInstruction extends UnboundInstruction implements ConstantInstruction.IntrinsicConstantInstruction { - final ConstantDesc constant; - public UnboundIntrinsicConstantInstruction(Opcode op) { super(op); - constant = op.constantValue(); } @Override public ConstantDesc constantValue() { - return constant; + return BytecodeHelpers.intrinsicConstantValue(op); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 272950c048d16..9f9fcd8d91af3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -409,60 +410,14 @@ public boolean equalsString(String s) { @Override void writeTo(BufWriterImpl pool) { + pool.writeU1(tag); if (rawBytes != null) { - pool.writeU1(tag); pool.writeU2(rawLen); pool.writeBytes(rawBytes, offset, rawLen); } else { // state == STRING and no raw bytes - if (stringValue.length() > 65535) { - throw new IllegalArgumentException("string too long"); - } - pool.writeU1(tag); - pool.writeU2(charLen); - for (int i = 0; i < charLen; ++i) { - char c = stringValue.charAt(i); - if (c >= '\001' && c <= '\177') { - // Optimistic writing -- hope everything is bytes - // If not, we bail out, and alternate path patches the length - pool.writeU1((byte) c); - } - else { - int charLength = stringValue.length(); - int byteLength = i; - char c1; - for (int j = i; j < charLength; ++j) { - c1 = (stringValue).charAt(j); - if (c1 >= '\001' && c1 <= '\177') { - byteLength++; - } else if (c1 > '\u07FF') { - byteLength += 3; - } else { - byteLength += 2; - } - } - if (byteLength > 65535) { - throw new IllegalArgumentException(); - } - int byteLengthFinal = byteLength; - pool.patchU2(pool.size() - i - 2, byteLengthFinal); - for (int j = i; j < charLength; ++j) { - c1 = (stringValue).charAt(j); - if (c1 >= '\001' && c1 <= '\177') { - pool.writeU1((byte) c1); - } else if (c1 > '\u07FF') { - pool.writeU1((byte) (0xE0 | c1 >> 12 & 0xF)); - pool.writeU1((byte) (0x80 | c1 >> 6 & 0x3F)); - pool.writeU1((byte) (0x80 | c1 & 0x3F)); - } else { - pool.writeU1((byte) (0xC0 | c1 >> 6 & 0x1F)); - pool.writeU1((byte) (0x80 | c1 & 0x3F)); - } - } - break; - } - } + pool.writeUTF(stringValue); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java index 66e974b4a51b6..b28bcc0b4b56f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java @@ -85,7 +85,7 @@ public CodeBuilder with(CodeElement element) { hasInstructions |= element instanceof Instruction; if (reachable) { - if (element instanceof Instruction i && i.opcode().isUnconditionalBranch()) + if (element instanceof Instruction i && BytecodeHelpers.isUnconditionalBranch(i.opcode())) reachable = false; } else if (element instanceof LabelTarget) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 1ce28e6bc8a2d..1ca69db472f09 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +35,11 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.PoolEntry; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + public final class BufWriterImpl implements BufWriter { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private final ConstantPoolBuilder constantPool; private final ClassFileImpl context; @@ -152,6 +157,52 @@ public void writeBytes(BufWriterImpl other) { writeBytes(other.elems, 0, other.offset); } + @SuppressWarnings("deprecation") + void writeUTF(String str) { + int strlen = str.length(); + int countNonZeroAscii = JLA.countNonZeroAscii(str); + int utflen = strlen; + if (countNonZeroAscii != strlen) { + for (int i = countNonZeroAscii; i < strlen; i++) { + int c = str.charAt(i); + if (c >= 0x80 || c == 0) + utflen += (c >= 0x800) ? 2 : 1; + } + } + if (utflen > 65535) { + throw new IllegalArgumentException("string too long"); + } + reserveSpace(utflen + 2); + + int offset = this.offset; + byte[] elems = this.elems; + + elems[offset ] = (byte) (utflen >> 8); + elems[offset + 1] = (byte) utflen; + offset += 2; + + str.getBytes(0, countNonZeroAscii, elems, offset); + offset += countNonZeroAscii; + + for (int i = countNonZeroAscii; i < strlen; ++i) { + char c = str.charAt(i); + if (c >= '\001' && c <= '\177') { + elems[offset++] = (byte) c; + } else if (c > '\u07FF') { + elems[offset ] = (byte) (0xE0 | c >> 12 & 0xF); + elems[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F); + elems[offset + 2] = (byte) (0x80 | c & 0x3F); + offset += 3; + } else { + elems[offset ] = (byte) (0xC0 | c >> 6 & 0x1F); + elems[offset + 1] = (byte) (0x80 | c & 0x3F); + offset += 2; + } + } + + this.offset = offset; + } + @Override public void writeBytes(byte[] arr, int start, int length) { reserveSpace(length); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index e52d198e1f423..75991531c319f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -46,6 +46,11 @@ import java.lang.classfile.constantpool.MethodHandleEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; +import static java.lang.classfile.ClassFile.*; + +/** + * Note: This class switches on opcode.bytecode for code size + */ public class BytecodeHelpers { private BytecodeHelpers() { @@ -236,7 +241,7 @@ public static Opcode reverseBranchOpcode(Opcode op) { case IF_ACMPNE -> Opcode.IF_ACMPEQ; case IFNULL -> Opcode.IFNONNULL; case IFNONNULL -> Opcode.IFNULL; - default -> throw new IllegalArgumentException("Unknown branch instruction: " + op); + default -> throw Util.badOpcodeKindException(op, Opcode.Kind.BRANCH); }; } @@ -277,6 +282,29 @@ public static Opcode convertOpcode(TypeKind from, TypeKind to) { }; } + public static TypeKind convertFromType(Opcode opcode) { + return switch (opcode) { + case I2D, I2F, I2L, I2B, I2C, I2S -> TypeKind.INT; + case L2D, L2F, L2I -> TypeKind.LONG; + case F2D, F2I, F2L -> TypeKind.FLOAT; + case D2F, D2I, D2L -> TypeKind.DOUBLE; + default -> throw Util.badOpcodeKindException(opcode, Opcode.Kind.CONVERT); + }; + } + + public static TypeKind convertToType(Opcode opcode) { + return switch (opcode) { + case I2B -> TypeKind.BYTE; + case I2C -> TypeKind.CHAR; + case I2S -> TypeKind.SHORT; + case L2I, F2I, D2I -> TypeKind.INT; + case I2L, F2L, D2L -> TypeKind.LONG; + case I2F, L2F, D2F -> TypeKind.FLOAT; + case I2D, L2D, F2D -> TypeKind.DOUBLE; + default -> throw Util.badOpcodeKindException(opcode, Opcode.Kind.CONVERT); + }; + } + public static void validateSipush(int value) { if (value != (short) value) throw new IllegalArgumentException( @@ -358,4 +386,145 @@ public static LoadableConstantEntry constantEntry(ConstantPoolBuilder constantPo } throw new UnsupportedOperationException("not yet: " + constantValue); } + + public static ConstantDesc intrinsicConstantValue(Opcode opcode) { + return switch (opcode) { + case ACONST_NULL -> ConstantDescs.NULL; + case ICONST_M1 -> -1; + case ICONST_0 -> 0; + case ICONST_1 -> 1; + case ICONST_2 -> 2; + case ICONST_3 -> 3; + case ICONST_4 -> 4; + case ICONST_5 -> 5; + case LCONST_0 -> 0L; + case LCONST_1 -> 1L; + case FCONST_0 -> 0F; + case FCONST_1 -> 1F; + case FCONST_2 -> 2F; + case DCONST_0 -> 0D; + case DCONST_1 -> 1D; + default -> throw Util.badOpcodeKindException(opcode, Opcode.Kind.CONSTANT); + }; + } + + public static TypeKind intrinsicConstantType(Opcode opcode) { + return switch (opcode) { + case ACONST_NULL -> TypeKind.REFERENCE; + case ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5 -> TypeKind.INT; + case LCONST_0, LCONST_1 -> TypeKind.LONG; + case FCONST_0, FCONST_1, FCONST_2 -> TypeKind.FLOAT; + case DCONST_0, DCONST_1 -> TypeKind.DOUBLE; + default -> throw Util.badOpcodeKindException(opcode, Opcode.Kind.CONSTANT); + }; + } + + public static boolean isUnconditionalBranch(Opcode opcode) { + return switch (opcode) { + case GOTO, ATHROW, GOTO_W, LOOKUPSWITCH, TABLESWITCH -> true; + default -> opcode.kind() == Opcode.Kind.RETURN; + }; + } + + // Must check Opcode.sizeIfFixed() == 1 before call! + public static int intrinsicLoadSlot(Opcode loadOpcode) { + return switch (loadOpcode) { + case ILOAD_0, LLOAD_0, FLOAD_0, DLOAD_0, ALOAD_0 -> 0; + case ILOAD_1, LLOAD_1, FLOAD_1, DLOAD_1, ALOAD_1 -> 1; + case ILOAD_2, LLOAD_2, FLOAD_2, DLOAD_2, ALOAD_2 -> 2; + case ILOAD_3, LLOAD_3, FLOAD_3, DLOAD_3, ALOAD_3 -> 3; + default -> throw Util.badOpcodeKindException(loadOpcode, Opcode.Kind.LOAD); + }; + } + + // Must check Opcode.sizeIfFixed() == 1 before call! + public static int intrinsicStoreSlot(Opcode storeOpcode) { + return switch (storeOpcode) { + case ISTORE_0, LSTORE_0, FSTORE_0, DSTORE_0, ASTORE_0 -> 0; + case ISTORE_1, LSTORE_1, FSTORE_1, DSTORE_1, ASTORE_1 -> 1; + case ISTORE_2, LSTORE_2, FSTORE_2, DSTORE_2, ASTORE_2 -> 2; + case ISTORE_3, LSTORE_3, FSTORE_3, DSTORE_3, ASTORE_3 -> 3; + default -> throw Util.badOpcodeKindException(storeOpcode, Opcode.Kind.STORE); + }; + } + + public static TypeKind loadType(Opcode loadOpcode) { + // Note: 0xFF handles wide pseudo-opcodes + return switch (loadOpcode.bytecode() & 0xFF) { + case ILOAD, ILOAD_0, ILOAD_1, ILOAD_2, ILOAD_3 -> TypeKind.INT; + case LLOAD, LLOAD_0, LLOAD_1, LLOAD_2, LLOAD_3 -> TypeKind.LONG; + case FLOAD, FLOAD_0, FLOAD_1, FLOAD_2, FLOAD_3 -> TypeKind.FLOAT; + case DLOAD, DLOAD_0, DLOAD_1, DLOAD_2, DLOAD_3 -> TypeKind.DOUBLE; + case ALOAD, ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3 -> TypeKind.REFERENCE; + default -> throw Util.badOpcodeKindException(loadOpcode, Opcode.Kind.LOAD); + }; + } + + public static TypeKind storeType(Opcode storeOpcode) { + // Note: 0xFF handles wide pseudo-opcodes + return switch (storeOpcode.bytecode() & 0xFF) { + case ISTORE, ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3 -> TypeKind.INT; + case LSTORE, LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3 -> TypeKind.LONG; + case FSTORE, FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3 -> TypeKind.FLOAT; + case DSTORE, DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3 -> TypeKind.DOUBLE; + case ASTORE, ASTORE_0, ASTORE_1, ASTORE_2, ASTORE_3 -> TypeKind.REFERENCE; + default -> throw Util.badOpcodeKindException(storeOpcode, Opcode.Kind.STORE); + }; + } + + public static TypeKind arrayLoadType(Opcode arrayLoadOpcode) { + return switch (arrayLoadOpcode) { + case IALOAD -> TypeKind.INT; + case LALOAD -> TypeKind.LONG; + case FALOAD -> TypeKind.FLOAT; + case DALOAD -> TypeKind.DOUBLE; + case AALOAD -> TypeKind.REFERENCE; + case BALOAD -> TypeKind.BYTE; + case CALOAD -> TypeKind.CHAR; + case SALOAD -> TypeKind.SHORT; + default -> throw Util.badOpcodeKindException(arrayLoadOpcode, Opcode.Kind.ARRAY_LOAD); + }; + } + + public static TypeKind arrayStoreType(Opcode arrayStoreOpcode) { + return switch (arrayStoreOpcode) { + case IASTORE -> TypeKind.INT; + case LASTORE -> TypeKind.LONG; + case FASTORE -> TypeKind.FLOAT; + case DASTORE -> TypeKind.DOUBLE; + case AASTORE -> TypeKind.REFERENCE; + case BASTORE -> TypeKind.BYTE; + case CASTORE -> TypeKind.CHAR; + case SASTORE -> TypeKind.SHORT; + default -> throw Util.badOpcodeKindException(arrayStoreOpcode, Opcode.Kind.ARRAY_STORE); + }; + } + + public static TypeKind returnType(Opcode returnOpcode) { + return switch (returnOpcode) { + case IRETURN -> TypeKind.INT; + case LRETURN -> TypeKind.LONG; + case FRETURN -> TypeKind.FLOAT; + case DRETURN -> TypeKind.DOUBLE; + case ARETURN -> TypeKind.REFERENCE; + case RETURN -> TypeKind.VOID; + default -> throw Util.badOpcodeKindException(returnOpcode, Opcode.Kind.RETURN); + }; + } + + public static TypeKind operatorOperandType(Opcode operationOpcode) { + return switch (operationOpcode) { + case IADD, ISUB, IMUL, IDIV, IREM, INEG, + ISHL, ISHR, IUSHR, IAND, IOR, IXOR, + ARRAYLENGTH -> TypeKind.INT; + case LADD, LSUB, LMUL, LDIV, LREM, LNEG, + LSHL, LSHR, LUSHR, LAND, LOR, LXOR, + LCMP -> TypeKind.LONG; + case FADD, FSUB, FMUL, FDIV, FREM, FNEG, + FCMPL, FCMPG -> TypeKind.FLOAT; + case DADD, DSUB, DMUL, DDIV, DREM, DNEG, + DCMPL, DCMPG -> TypeKind.DOUBLE; + default -> throw Util.badOpcodeKindException(operationOpcode, Opcode.Kind.OPERATOR); + }; + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index 8be7e92f5b600..68c93249c1b2d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -55,13 +55,13 @@ public final class CodeImpl case ARRAY_STORE -> ArrayStoreInstruction.of(o); case CONSTANT -> ConstantInstruction.ofIntrinsic(o); case CONVERT -> ConvertInstruction.of(o); - case LOAD -> LoadInstruction.of(o, o.slot()); + case LOAD -> LoadInstruction.of(o, BytecodeHelpers.intrinsicLoadSlot(o)); case MONITOR -> MonitorInstruction.of(o); case NOP -> NopInstruction.of(); case OPERATOR -> OperatorInstruction.of(o); case RETURN -> ReturnInstruction.of(o); case STACK -> StackInstruction.of(o); - case STORE -> StoreInstruction.of(o, o.slot()); + case STORE -> StoreInstruction.of(o, BytecodeHelpers.intrinsicStoreSlot(o)); case THROW_EXCEPTION -> ThrowInstruction.of(); default -> throw new AssertionError("invalid opcode: " + o); }; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index 609333048d0d3..bdee788c9da77 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -35,9 +35,10 @@ import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.lang.reflect.AccessFlag; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.Objects; -import java.util.TreeMap; import static java.lang.classfile.ClassFile.*; @@ -46,6 +47,7 @@ public class StackMapDecoder { private static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, SAME_EXTENDED = 251; + private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = new StackMapFrameInfo[0]; private final ClassReader classReader; private final int pos; @@ -103,15 +105,20 @@ public static void writeFrames(BufWriter b, List entries) { mi.methodTypeSymbol(), (mi.methodFlags() & ACC_STATIC) != 0); int prevOffset = -1; - var map = new TreeMap(); + // avoid using method handles due to early bootstrap + StackMapFrameInfo[] infos = entries.toArray(NO_STACK_FRAME_INFOS); //sort by resolved label offsets first to allow unordered entries - for (var fr : entries) { - map.put(dcb.labelToBci(fr.target()), fr); - } - b.writeU2(map.size()); - for (var me : map.entrySet()) { - int offset = me.getKey(); - var fr = me.getValue(); + Arrays.sort(infos, new Comparator() { + public int compare(final StackMapFrameInfo o1, final StackMapFrameInfo o2) { + return Integer.compare(dcb.labelToBci(o1.target()), dcb.labelToBci(o2.target())); + } + }); + b.writeU2(infos.length); + for (var fr : infos) { + int offset = dcb.labelToBci(fr.target()); + if (offset == prevOffset) { + throw new IllegalArgumentException("Duplicated stack frame bytecode index: " + offset); + } writeFrame(buf, offset - prevOffset - 1, prevLocals, fr); prevOffset = offset; prevLocals = fr.locals(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index a064c40be30a9..2d9e27b8d74d5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -185,8 +185,12 @@ public static List moduleEntryList(List list) public static void checkKind(Opcode op, Opcode.Kind k) { if (op.kind() != k) - throw new IllegalArgumentException( - String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k)); + throw badOpcodeKindException(op, k); + } + + public static IllegalArgumentException badOpcodeKindException(Opcode op, Opcode.Kind k) { + return new IllegalArgumentException( + String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k)); } public static int flagsToBits(AccessFlag.Location location, Collection flags) { diff --git a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java index f58bead542f83..5640f849ab6b1 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java +++ b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java @@ -35,12 +35,16 @@ import java.util.List; import java.util.Set; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import static jdk.internal.constant.PrimitiveClassDescImpl.*; /** * Helper methods for the implementation of {@code java.lang.constant}. */ public final class ConstantUtils { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + /** an empty constant descriptor */ public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0]; public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0]; @@ -66,7 +70,7 @@ private ConstantUtils() {} * @param binaryName a binary name */ public static ClassDesc binaryNameToDesc(String binaryName) { - return ReferenceClassDescImpl.ofValidated("L" + binaryToInternal(binaryName) + ";"); + return ReferenceClassDescImpl.ofValidated(concat("L", binaryToInternal(binaryName), ";")); } /** @@ -378,4 +382,8 @@ private static IllegalArgumentException maxArrayTypeDescDimensions() { "Cannot create an array type descriptor with more than %d dimensions", ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS)); } + + public static String concat(String prefix, Object value, String suffix) { + return JLA.concat(prefix, value, suffix); + } } 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 5d43c28a66711..83b11b7ce686b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -304,20 +304,25 @@ public boolean isNative() { @Override public final Optional asOverlappingSlice(MemorySegment other) { - AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other); - if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or heap + final AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other); + if (overlaps(that)) { + final long offsetToThat = that.address() - this.address(); + final long newOffset = offsetToThat >= 0 ? offsetToThat : 0; + return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat))); + } + return Optional.empty(); + } + + @ForceInline + private boolean overlaps(AbstractMemorySegmentImpl that) { + if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or the same heap segment final long thisStart = this.unsafeGetOffset(); final long thatStart = that.unsafeGetOffset(); final long thisEnd = thisStart + this.byteSize(); final long thatEnd = thatStart + that.byteSize(); - - if (thisStart < thatEnd && thisEnd > thatStart) { //overlap occurs - long offsetToThat = that.address() - this.address(); - long newOffset = offsetToThat >= 0 ? offsetToThat : 0; - return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat))); - } + return (thisStart < thatEnd && thisEnd > thatStart); //overlap occurs? } - return Optional.empty(); + return false; } @Override @@ -645,6 +650,64 @@ private static Object bufferRef(Buffer buffer) { } } + // COPY_NATIVE_THRESHOLD must be a power of two and should be greater than 2^3 + private static final long COPY_NATIVE_THRESHOLD = 1 << 6; + + @ForceInline + public static void copy(AbstractMemorySegmentImpl src, long srcOffset, + AbstractMemorySegmentImpl dst, long dstOffset, + long size) { + + Utils.checkNonNegativeIndex(size, "size"); + // Implicit null check for src and dst + src.checkAccess(srcOffset, size, true); + dst.checkAccess(dstOffset, size, false); + + if (size <= 0) { + // Do nothing + } else if (size < COPY_NATIVE_THRESHOLD && !src.overlaps(dst)) { + // 0 < size < FILL_NATIVE_LIMIT : 0...0X...XXXX + // + // Strictly, we could check for !src.asSlice(srcOffset, size).overlaps(dst.asSlice(dstOffset, size) but + // this is a bit slower and it likely very unusual there is any difference in the outcome. Also, if there + // is an overlap, we could tolerate one particular direction of overlap (but not the other). + + // 0...0X...X000 + final int limit = (int) (size & (COPY_NATIVE_THRESHOLD - 8)); + int offset = 0; + for (; offset < limit; offset += 8) { + final long v = SCOPED_MEMORY_ACCESS.getLong(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putLong(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + } + int remaining = (int) size - offset; + // 0...0X00 + if (remaining >= 4) { + final int v = SCOPED_MEMORY_ACCESS.getInt(src.sessionImpl(), src.unsafeGetBase(),src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putInt(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + offset += 4; + remaining -= 4; + } + // 0...00X0 + if (remaining >= 2) { + final short v = SCOPED_MEMORY_ACCESS.getShort(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putShort(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + offset += 2; + remaining -=2; + } + // 0...000X + if (remaining == 1) { + final byte v = SCOPED_MEMORY_ACCESS.getByte(src.sessionImpl(), src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset + offset); + SCOPED_MEMORY_ACCESS.putByte(dst.sessionImpl(), dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset + offset, v); + } + // We have now fully handled 0...0X...XXXX + } else { + // For larger sizes, the transition to native code pays off + SCOPED_MEMORY_ACCESS.copyMemory(src.sessionImpl(), dst.sessionImpl(), + src.unsafeGetBase(), src.unsafeGetOffset() + srcOffset, + dst.unsafeGetBase(), dst.unsafeGetOffset() + dstOffset, size); + } + } + @ForceInline public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset, MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index b2527a7fc2c1f..00e40c5f58761 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1789,7 +1789,8 @@ private char[] promptForKeyPass(String alias, String orig, char[] origPass) thro */ private char[] promptForCredential() throws Exception { // Handle password supplied via stdin - if (System.console() == null) { + Console console = System.console(); + if (console == null || !console.isTerminal()) { char[] importPass = Password.readPassword(System.in); passwords.add(importPass); return importPass; diff --git a/src/java.base/share/native/include/jni.h b/src/java.base/share/native/include/jni.h index c85da1bc67f2e..6bbc71ded1f8d 100644 --- a/src/java.base/share/native/include/jni.h +++ b/src/java.base/share/native/include/jni.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -775,6 +775,12 @@ struct JNINativeInterface_ { jboolean (JNICALL *IsVirtualThread) (JNIEnv* env, jobject obj); + + /* Large UTF8 Support */ + + jlong (JNICALL *GetStringUTFLengthAsLong) + (JNIEnv *env, jstring str); + }; /* @@ -1623,6 +1629,9 @@ struct JNIEnv_ { jsize GetStringUTFLength(jstring str) { return functions->GetStringUTFLength(this,str); } + jlong GetStringUTFLengthAsLong(jstring str) { + return functions->GetStringUTFLengthAsLong(this,str); + } const char* GetStringUTFChars(jstring str, jboolean *isCopy) { return functions->GetStringUTFChars(this,str,isCopy); } @@ -1993,6 +2002,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved); #define JNI_VERSION_19 0x00130000 #define JNI_VERSION_20 0x00140000 #define JNI_VERSION_21 0x00150000 +#define JNI_VERSION_24 0x00180000 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/java.base/unix/native/libnio/MappedMemoryUtils.c b/src/java.base/unix/native/libnio/MappedMemoryUtils.c index cdd8edff22a6c..6cfa3b47f84e4 100644 --- a/src/java.base/unix/native/libnio/MappedMemoryUtils.c +++ b/src/java.base/unix/native/libnio/MappedMemoryUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,9 +40,8 @@ typedef unsigned char mincore_vec_t; typedef char mincore_vec_t; #endif -JNIEXPORT jboolean JNICALL -Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, - jlong len, jlong numPages) +jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) { jboolean loaded = JNI_TRUE; int result = 0; @@ -80,8 +79,7 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, +void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, jlong len) { char *a = (char *)jlong_to_ptr(address); @@ -91,9 +89,8 @@ Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, } } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, - jlong len) +void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, + jlong len) { char *a = (char *)jlong_to_ptr(address); int result = madvise((caddr_t)a, (size_t)len, MADV_DONTNEED); @@ -102,8 +99,7 @@ Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, } } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, +void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, jlong address, jlong len) { void* a = (void *)jlong_to_ptr(address); @@ -112,3 +108,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, JNU_ThrowIOExceptionWithMessageAndLastError(env, "msync with parameter MS_SYNC failed"); } } + +#define FD "Ljava/io/FileDescriptor;" + +static JNINativeMethod methods[] = { + {"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0}, + {"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0}, + {"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0}, + {"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0}, +}; + +JNIEXPORT void JNICALL +Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls) +{ + (*env)->RegisterNatives(env, cls, + methods, sizeof(methods)/sizeof(methods[0])); +} diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java index cf58d980bbe75..10e02b4ba727a 100644 --- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -490,12 +490,26 @@ public String canonicalize(String path) throws IOException { return path; return "" + ((char) (c-32)) + ':' + '\\'; } - return canonicalize0(path); + String canonicalPath = canonicalize0(path); + String finalPath = null; + try { + finalPath = getFinalPath(canonicalPath); + } catch (IOException ignored) { + finalPath = canonicalPath; + } + return finalPath; } private native String canonicalize0(String path) throws IOException; + private String getFinalPath(String path) throws IOException { + return getFinalPath0(path); + } + + private native String getFinalPath0(String path) + throws IOException; + /* -- Attribute accessors -- */ diff --git a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c index 43ce921627102..2598eaa6fec9a 100644 --- a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c +++ b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,31 +46,15 @@ static struct { jfieldID path; } ids; -/** - * GetFinalPathNameByHandle is available on Windows Vista and newer - */ -typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); -static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; - JNIEXPORT void JNICALL Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls) { - HMODULE handle; jclass fileClass; fileClass = (*env)->FindClass(env, "java/io/File"); CHECK_NULL(fileClass); ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;"); CHECK_NULL(ids.path); - - // GetFinalPathNameByHandle requires Windows Vista or newer - if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), - (LPCWSTR)&CreateFileW, &handle) != 0) - { - GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc) - GetProcAddress(handle, "GetFinalPathNameByHandleW"); - } } /* -- Path operations -- */ @@ -88,10 +72,6 @@ static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path) WCHAR *result; DWORD error; - /* Need Windows Vista or newer to get the final path */ - if (GetFinalPathNameByHandle_func == NULL) - return NULL; - h = CreateFileW(path, FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | @@ -109,13 +89,13 @@ static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path) */ result = (WCHAR*)malloc(MAX_PATH * sizeof(WCHAR)); if (result != NULL) { - DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0); + DWORD len = GetFinalPathNameByHandleW(h, result, MAX_PATH, 0); if (len >= MAX_PATH) { /* retry with a buffer of the right size */ WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR)); if (newResult != NULL) { result = newResult; - len = (*GetFinalPathNameByHandle_func)(h, result, len, 0); + len = GetFinalPathNameByHandleW(h, result, len, 0); } else { len = 0; JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); @@ -351,6 +331,25 @@ Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this, return rv; } +JNIEXPORT jstring JNICALL +Java_java_io_WinNTFileSystem_getFinalPath0(JNIEnv* env, jobject this, jstring pathname) { + jstring rv = NULL; + + WITH_UNICODE_STRING(env, pathname, path) { + WCHAR* finalPath = getFinalPath(env, path); + if (finalPath != NULL) { + rv = (*env)->NewString(env, finalPath, (jsize)wcslen(finalPath)); + free(finalPath); + } + } END_UNICODE_STRING(env, path); + + if (rv == NULL && !(*env)->ExceptionCheck(env)) { + JNU_ThrowIOExceptionWithLastError(env, "Bad pathname"); + } + + return rv; +} + /* -- Attribute accessors -- */ /* Check whether or not the file name in "path" is a Windows reserved diff --git a/src/java.base/windows/native/libnio/MappedMemoryUtils.c b/src/java.base/windows/native/libnio/MappedMemoryUtils.c index 5017ca63a9281..6e43dfb505f8d 100644 --- a/src/java.base/windows/native/libnio/MappedMemoryUtils.c +++ b/src/java.base/windows/native/libnio/MappedMemoryUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,9 +30,8 @@ #include "java_nio_MappedMemoryUtils.h" #include -JNIEXPORT jboolean JNICALL -Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, - jlong len, jlong numPages) +jboolean JNICALL MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) { jboolean loaded = JNI_FALSE; /* Information not available? @@ -43,22 +42,19 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres return loaded; } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, +void JNICALL MappedMemoryUtils_load0(JNIEnv *env, jobject obj, jlong address, jlong len) { // no madvise available } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, - jlong len) +void JNICALL MappedMemoryUtils_unload0(JNIEnv *env, jobject obj, jlong address, + jlong len) { // no madvise available } -JNIEXPORT void JNICALL -Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, +void JNICALL MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, jlong address, jlong len) { void *a = (void *) jlong_to_ptr(address); @@ -106,3 +102,19 @@ Java_java_nio_MappedMemoryUtils_force0(JNIEnv *env, jobject obj, jobject fdo, JNU_ThrowIOExceptionWithLastError(env, "Flush failed"); } } + +#define FD "Ljava/io/FileDescriptor;" + +static JNINativeMethod methods[] = { + {"isLoaded0", "(JJJ)Z", (void *)&MappedMemoryUtils_isLoaded0}, + {"load0", "(JJ)V", (void *)&MappedMemoryUtils_load0}, + {"unload0", "(JJ)V", (void *)&MappedMemoryUtils_unload0}, + {"force0", "(" FD "JJ)V", (void *)&MappedMemoryUtils_force0}, +}; + +JNIEXPORT void JNICALL +Java_java_nio_MappedMemoryUtils_registerNatives(JNIEnv *env, jclass cls) +{ + (*env)->RegisterNatives(env, cls, + methods, sizeof(methods)/sizeof(methods[0])); +} diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m index a8a821423de44..4d8f1c765e65f 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, 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 @@ -117,12 +117,20 @@ + (ApplicationDelegate *)sharedDelegate { // don't install the EAWT delegate if another kind of NSApplication is installed, like say, Safari BOOL shouldInstall = NO; BOOL overrideDelegate = (getenv("AWT_OVERRIDE_NSDELEGATE") != NULL); + BOOL isApplicationOwner = NO; if (NSApp != nil) { if ([NSApp isMemberOfClass:[NSApplication class]] && overrideDelegate) shouldInstall = YES; - if ([NSApp isKindOfClass:[NSApplicationAWT class]]) shouldInstall = YES; + if ([NSApp isKindOfClass:[NSApplicationAWT class]]) { + shouldInstall = YES; + isApplicationOwner = YES; + } } checked = YES; - if (!shouldInstall) return nil; + if (!shouldInstall) { + [ThreadUtilities setApplicationOwner:NO]; + return nil; + } + [ThreadUtilities setApplicationOwner:isApplicationOwner]; sApplicationDelegate = [[ApplicationDelegate alloc] init]; return sApplicationDelegate; diff --git a/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.h b/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.h index 24fb2f61d8625..8db2831ad619b 100644 --- a/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.h +++ b/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, 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 @@ -131,6 +131,7 @@ __attribute__((visibility("default"))) + (JNIEnv*)getJNIEnvUncached; + (void)detachCurrentThread; + (void)setAppkitThreadGroup:(jobject)group; ++ (void)setApplicationOwner:(BOOL)owner; + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block; + (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait; diff --git a/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.m b/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.m index deb179ece570a..a64727c1a4d4e 100644 --- a/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.m +++ b/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, 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 @@ -31,6 +31,7 @@ // The following must be named "jvm", as there are extern references to it in AWT JavaVM *jvm = NULL; +static BOOL isNSApplicationOwner = NO; static JNIEnv *appKitEnv = NULL; static jobject appkitThreadGroup = NULL; static NSString* JavaRunLoopMode = @"AWTRunLoopMode"; @@ -59,12 +60,20 @@ + (void)initialize { nil]; } ++ (void)setApplicationOwner:(BOOL)owner { + isNSApplicationOwner = owner; +} + + (JNIEnv*)getJNIEnv { AWT_ASSERT_APPKIT_THREAD; - if (appKitEnv == NULL) { - attachCurrentThread((void **)&appKitEnv); + if (isNSApplicationOwner) { + if (appKitEnv == NULL) { + attachCurrentThread((void **)&appKitEnv); + } + return appKitEnv; + } else { + return [ThreadUtilities getJNIEnvUncached]; } - return appKitEnv; } + (JNIEnv*)getJNIEnvUncached { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index 90c051353686e..b9c2ce914d4ae 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -888,11 +888,7 @@ else if ("CheckBox.iconTextGap".equals(key) || } // Is it a stock icon ? - GTKStockIcon stockIcon = null; - synchronized (ICONS_MAP) { - stockIcon = ICONS_MAP.get(key); - } - + GTKStockIcon stockIcon = ICONS_MAP.get(key); if (stockIcon != null) { return stockIcon; } @@ -1179,27 +1175,28 @@ public Object createValue(UIDefaults table) { CLASS_SPECIFIC_MAP.put("EditorPane.caretForeground", "cursor-color"); CLASS_SPECIFIC_MAP.put("EditorPane.caretAspectRatio", "cursor-aspect-ratio"); - ICONS_MAP = new HashMap(); - ICONS_MAP.put("FileChooser.cancelIcon", new GTKStockIcon("gtk-cancel", 4)); - ICONS_MAP.put("FileChooser.okIcon", new GTKStockIcon("gtk-ok", 4)); - ICONS_MAP.put("OptionPane.yesIcon", new GTKStockIcon("gtk-yes", 4)); - ICONS_MAP.put("OptionPane.noIcon", new GTKStockIcon("gtk-no", 4)); - ICONS_MAP.put("OptionPane.cancelIcon", new GTKStockIcon("gtk-cancel", 4)); - ICONS_MAP.put("OptionPane.okIcon", new GTKStockIcon("gtk-ok", 4)); + Map iconsMap = new HashMap<>(); + iconsMap.put("FileChooser.cancelIcon", new GTKStockIcon("gtk-cancel", 4)); + iconsMap.put("FileChooser.okIcon", new GTKStockIcon("gtk-ok", 4)); + iconsMap.put("OptionPane.yesIcon", new GTKStockIcon("gtk-yes", 4)); + iconsMap.put("OptionPane.noIcon", new GTKStockIcon("gtk-no", 4)); + iconsMap.put("OptionPane.cancelIcon", new GTKStockIcon("gtk-cancel", 4)); + iconsMap.put("OptionPane.okIcon", new GTKStockIcon("gtk-ok", 4)); //check whether the gtk version is >= 3.10 as the Icon names were //changed from this version UNIXToolkit tk = (UNIXToolkit)Toolkit.getDefaultToolkit(); if (tk.checkGtkVersion(3, 10, 0)) { - ICONS_MAP.put("OptionPane.errorIcon", new GTKStockIcon("dialog-error", 6)); - ICONS_MAP.put("OptionPane.informationIcon", new GTKStockIcon("dialog-information", 6)); - ICONS_MAP.put("OptionPane.warningIcon", new GTKStockIcon("dialog-warning", 6)); - ICONS_MAP.put("OptionPane.questionIcon", new GTKStockIcon("dialog-question", 6)); + iconsMap.put("OptionPane.errorIcon", new GTKStockIcon("dialog-error", 6)); + iconsMap.put("OptionPane.informationIcon", new GTKStockIcon("dialog-information", 6)); + iconsMap.put("OptionPane.warningIcon", new GTKStockIcon("dialog-warning", 6)); + iconsMap.put("OptionPane.questionIcon", new GTKStockIcon("dialog-question", 6)); } else { - ICONS_MAP.put("OptionPane.errorIcon", new GTKStockIcon("gtk-dialog-error", 6)); - ICONS_MAP.put("OptionPane.informationIcon", new GTKStockIcon("gtk-dialog-info", 6)); - ICONS_MAP.put("OptionPane.warningIcon", new GTKStockIcon("gtk-dialog-warning", 6)); - ICONS_MAP.put("OptionPane.questionIcon", new GTKStockIcon("gtk-dialog-question", 6)); + iconsMap.put("OptionPane.errorIcon", new GTKStockIcon("gtk-dialog-error", 6)); + iconsMap.put("OptionPane.informationIcon", new GTKStockIcon("gtk-dialog-info", 6)); + iconsMap.put("OptionPane.warningIcon", new GTKStockIcon("gtk-dialog-warning", 6)); + iconsMap.put("OptionPane.questionIcon", new GTKStockIcon("gtk-dialog-question", 6)); } + ICONS_MAP = Collections.unmodifiableMap(iconsMap); } } diff --git a/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java b/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java index 544c1945701b5..5535fdd41c928 100644 --- a/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java +++ b/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Client.java @@ -144,7 +144,7 @@ final class DigestMD5Client extends DigestMD5Base implements SaslClient { * combined protocol and host being used for authentication. * @param props The possibly null properties to be used by the SASL * mechanism to configure the authentication exchange. - * @param cbh The non-null CallbackHanlder object for callbacks + * @param cbh The non-null CallbackHandler object for callbacks * @throws SaslException if no authentication ID or password is supplied */ DigestMD5Client(String authzid, String protocol, String serverName, diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java index e3335dfb3c65c..2f310effc87f4 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,10 +56,6 @@ public AccessFlags(long flags) { public long getValue () { return flags; } - // Klass* flags - public boolean hasFinalizer () { return (flags & JVM_ACC_HAS_FINALIZER ) != 0; } - public boolean isCloneable () { return (flags & JVM_ACC_IS_CLONEABLE ) != 0; } - public void printOn(PrintStream tty) { // prints only .class flags and not the hotspot internal flags if (isPublic ()) tty.print("public " ); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index ce869afad8aca..5947e32861e0a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -230,6 +230,4 @@ public Klass arrayKlassImpl(boolean orNull) { public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } public boolean isSuper() { return getAccessFlagsObj().isSuper(); } public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } - public boolean hasFinalizer() { return getAccessFlagsObj().hasFinalizer(); } - public boolean isCloneable() { return getAccessFlagsObj().isCloneable(); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java index 21fca913a3e00..25f40ec443f50 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -103,12 +103,6 @@ public interface ClassConstants // flags actually put in .class file public static final long JVM_ACC_WRITTEN_FLAGS = 0x00007FFF; - // Klass* flags - // True if klass has a non-empty finalize() method - public static final long JVM_ACC_HAS_FINALIZER = 0x40000000; - // True if klass supports the Clonable interface - public static final long JVM_ACC_IS_CLONEABLE = 0x80000000; - // flags accepted by set_field_flags public static final long JVM_ACC_FIELD_FLAGS = 0x00008000 | JVM_ACC_WRITTEN_FLAGS; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 46e7280bbb7ca..91c9e73b532b9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -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 @@ -170,6 +170,11 @@ public int getAccessFlags() { return UNSAFE.getInt(getKlassPointer() + config.klassAccessFlagsOffset); } + public int getMiscFlags() { + HotSpotVMConfig config = config(); + return UNSAFE.getInt(getKlassPointer() + config.klassMiscFlagsOffset); + } + @Override public ResolvedJavaType getComponentType() { if (componentType == null) { @@ -373,7 +378,7 @@ public AssumptionResult hasFinalizableSubclass() { @Override public boolean hasFinalizer() { - return (getAccessFlags() & config().jvmAccHasFinalizer) != 0; + return (getMiscFlags() & config().jvmAccHasFinalizer) != 0; } @Override @@ -1110,7 +1115,7 @@ public ResolvedJavaField resolveField(UnresolvedJavaField unresolvedJavaField, R @Override public boolean isCloneableWithAllocation() { - return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0; + return (getMiscFlags() & config().jvmAccIsCloneableFast) != 0; } @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 954e1f6b20173..16d9cf3625ef6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -98,6 +98,7 @@ String getHostArchitectureName() { final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); final int instanceKlassAnnotationsOffset = getFieldOffset("InstanceKlass::_annotations", Integer.class, "Annotations*"); final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags._flags", Integer.class, "u2"); + final int klassMiscFlagsOffset = getFieldOffset("Klass::_misc_flags._flags", Integer.class, "u1"); final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int"); final int klassVtableLengthOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_length_offset", Integer.class, "int"); @@ -113,10 +114,10 @@ String getHostArchitectureName() { final int arrayU1DataOffset = getFieldOffset("Array::_data", Integer.class); final int arrayU2DataOffset = getFieldOffset("Array::_data", Integer.class); - final int jvmAccHasFinalizer = getConstant("JVM_ACC_HAS_FINALIZER", Integer.class); + final int jvmAccHasFinalizer = getConstant("KlassFlags::_misc_has_finalizer", Integer.class); final int jvmFieldFlagInternalShift = getConstant("FieldInfo::FieldFlags::_ff_injected", Integer.class); final int jvmFieldFlagStableShift = getConstant("FieldInfo::FieldFlags::_ff_stable", Integer.class); - final int jvmAccIsCloneableFast = getConstant("JVM_ACC_IS_CLONEABLE_FAST", Integer.class); + final int jvmAccIsCloneableFast = getConstant("KlassFlags::_misc_is_cloneable_fast", Integer.class); // These modifiers are not public in Modifier so we get them via vmStructs. final int jvmAccSynthetic = getConstant("JVM_ACC_SYNTHETIC", Integer.class); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index 84672926cf81a..7efaec8769245 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -109,7 +109,7 @@ protected Content getSummaryLink(Element member) { } String signature = utils.flatSignature((ExecutableElement) member, typeElement); if (signature.length() > 2) { - content.add(new HtmlTree(HtmlTag.WBR)); + content.add(HtmlTree.WBR()); } content.add(signature); @@ -144,7 +144,7 @@ protected void addTypeParameters(ExecutableElement member, Content target) { // Add explicit line break between method type parameters and // return type in member summary table to avoid random wrapping. if (typeParameters.charCount() > 10) { - target.add(new HtmlTree(HtmlTag.BR)); + target.add(HtmlTree.BR()); } else { target.add(Entity.NO_BREAK_SPACE); } @@ -233,7 +233,7 @@ protected void addParameters(ExecutableElement member, Content target) { Content params = getParameters(member, false); if (params.charCount() > 2) { // only add for non-empty parameters - target.add(new HtmlTree(HtmlTag.WBR)); + target.add(HtmlTree.WBR()); } target.add(params); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index e2b81bb39822d..59a8f58923085 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -451,7 +451,7 @@ protected abstract void addInheritedSummaryLink(TypeElement typeElement, */ protected void addModifiersAndType(Element member, TypeMirror type, Content target) { - var code = new HtmlTree(HtmlTag.CODE); + var code = HtmlTree.CODE(); addModifiers(member, code); if (type == null) { code.add(switch (member.getKind()) { @@ -670,7 +670,7 @@ public Content getInheritedSummaryHeader(TypeElement tElement) { * @return the inherited summary links */ public Content getInheritedSummaryLinks() { - return new HtmlTree(HtmlTag.CODE); + return HtmlTree.CODE(); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java index 594132743eb0f..915dbd7627a73 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java @@ -79,10 +79,9 @@ protected AbstractTreeWriter(HtmlConfiguration configuration, protected void addLevelInfo(TypeElement parent, Collection collection, Hierarchy hierarchy, Content content) { if (!collection.isEmpty()) { - var ul = new HtmlTree(HtmlTag.UL); + var ul = HtmlTree.UL(); for (TypeElement local : collection) { - var li = new HtmlTree(HtmlTag.LI); - li.setStyle(HtmlStyles.circle); + var li = HtmlTree.LI(HtmlStyles.circle); addPartialInfo(local, li); addExtendsImplements(parent, local, li); addLevelInfo(local, hierarchy.subtypes(local), hierarchy, li); // Recurse diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java index ac953dccb55df..d10478fb3bad5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java @@ -423,7 +423,7 @@ protected HtmlTree getClassUseHeader() { HtmlTree body = getBody(getWindowTitle(title)); ContentBuilder headingContent = new ContentBuilder(); headingContent.add(contents.getContent("doclet.ClassUse_Title", cltype)); - headingContent.add(new HtmlTree(HtmlTag.BR)); + headingContent.add(HtmlTree.BR()); headingContent.add(clname); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, headingContent); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java index 8218e5128be3b..7b271485f1f4a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java @@ -165,7 +165,7 @@ protected void buildClassInfo(Content target) { buildInterfaceUsageInfo(c); buildNestedClassInfo(c); buildFunctionalInterfaceInfo(c); - c.add(new HtmlTree(HtmlTag.HR)); + c.add(HtmlTree.HR()); var div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildClassSignature(div); buildDeprecationInfo(div); @@ -461,7 +461,7 @@ private Content getTypeParameters() { var first = true; for (TypeParameterElement t : typeParams) { if (!first) { - content.add(",").add(new HtmlTree(HtmlTag.WBR)); + content.add(",").add(HtmlTree.WBR()); } var typeParamLink = getLink(linkInfo.forType(t.asType())); content.add(needsId @@ -689,11 +689,9 @@ public Void visitType(TypeElement e, Void p) { protected void addFunctionalInterfaceInfo (Content target) { if (utils.isFunctionalInterface(typeElement)) { - var dl = HtmlTree.DL(HtmlStyles.notes); - dl.add(HtmlTree.DT(contents.functionalInterface)); - var dd = new HtmlTree(HtmlTag.DD); - dd.add(contents.functionalInterfaceMessage); - dl.add(dd); + var dl = HtmlTree.DL(HtmlStyles.notes) + .add(HtmlTree.DT(contents.functionalInterface)) + .add(HtmlTree.DD(contents.functionalInterfaceMessage)); target.add(dl); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java index cdae0e8d9115e..9731cd14e8855 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java @@ -414,7 +414,7 @@ void addConstantMembers(TypeElement typeElement, Collection fie */ private Content getTypeColumn(VariableElement member) { Content typeContent = new ContentBuilder(); - var code = new HtmlTree(HtmlTag.CODE) + var code = HtmlTree.CODE() .setId(htmlIds.forMember(currentTypeElement, member)); for (Modifier mod : member.getModifiers()) { code.add(Text.of(mod.toString())) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java index 11975404a5564..d1d04d4f7f10e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java @@ -300,7 +300,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { @Override protected void addSummaryType(Element member, Content content) { if (threeColumnSummary()) { - var code = new HtmlTree(HtmlTag.CODE); + var code = HtmlTree.CODE(); if (utils.isProtected(member)) { code.add("protected "); } else if (utils.isPrivate(member)) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java index 22e778d39868f..1687f891896a3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java @@ -105,11 +105,11 @@ protected void addHelpFileContents(Content content) { tableOfContents.addLink(HtmlIds.TOP_OF_PAGE, mainHeading); tableOfContents.pushNestedList(); content.add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, mainHeading)) - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(getNavigationSection()) - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(getPageKindSection()) - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(HtmlTree.SPAN(HtmlStyles.helpFootnote, getContent("doclet.help.footnote"))); tableOfContents.popNestedList(); @@ -255,7 +255,7 @@ private Content getPageKindSection() { getContent("doclet.help.class_interface.implementations"), getContent("doclet.help.class_interface.declaration"), getContent("doclet.help.class_interface.description"))) - .add(new HtmlTree(HtmlTag.BR)) + .add(HtmlTree.BR()) .add(newHelpSectionList( contents.nestedClassSummary, contents.enumConstantSummary, @@ -265,7 +265,7 @@ private Content getPageKindSection() { contents.methodSummary, contents.annotateTypeRequiredMemberSummaryLabel, contents.annotateTypeOptionalMemberSummaryLabel)) - .add(new HtmlTree(HtmlTag.BR)) + .add(HtmlTree.BR()) .add(newHelpSectionList( contents.enumConstantDetailLabel, contents.fieldDetailsLabel, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 235a0361b9233..fdf05489168f7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -685,7 +685,7 @@ public HtmlTree getFooter() { return (bottom == null || bottom.isEmpty()) ? null : HtmlTree.FOOTER() - .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.HR()) .add(HtmlTree.P(HtmlStyles.legalCopy, HtmlTree.SMALL( RawHtml.of(replaceDocRootDir(bottom))))); @@ -2405,7 +2405,7 @@ static String getGenerator(Class clazz) { * @return an HtmlTree for the BODY tag */ public HtmlTree getBody(String title) { - var body = new HtmlTree(HtmlTag.BODY).setStyle(getBodyStyle()); + var body = HtmlTree.BODY(getBodyStyle()); this.winTitle = title; // Don't print windowtitle script for overview-frame, allclasses-frame @@ -2601,7 +2601,7 @@ private Content withPreviewFeatures(String key, String className, String feature }); return contents.getContent(key, HtmlTree.CODE(Text.of(className)), - new HtmlTree(HtmlTag.EM).add(featureName), + HtmlTree.EM(featureName), featureCodes); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 494d5e22d6e10..bf210b91ea6eb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -395,14 +395,14 @@ protected Content getTypeParameterLinks(HtmlLinkInfo linkInfo) { } if (!vars.isEmpty()) { if (linkInfo.addLineBreakOpportunitiesInTypeParameters()) { - links.add(new HtmlTree(HtmlTag.WBR)); + links.add(HtmlTree.WBR()); } links.add("<"); boolean many = false; for (TypeMirror t : vars) { if (many) { links.add(","); - links.add(new HtmlTree(HtmlTag.WBR)); + links.add(HtmlTree.WBR()); if (linkInfo.addLineBreaksInTypeParameters()) { links.add(Text.NL); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java index e449ecebf40a2..a7afd9db85d09 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java @@ -92,7 +92,7 @@ public void buildPage() throws DocFileIOException { Script script = new Script("window.location.replace(") .appendStringLiteral(targetPath, '\'') .append(")"); - var metaRefresh = new HtmlTree(HtmlTag.META) + var metaRefresh = HtmlTree.of(HtmlTag.META) .put(HtmlAttr.HTTP_EQUIV, "Refresh") .put(HtmlAttr.CONTENT, "0;" + targetPath); head.addContent(script.asContent(), HtmlTree.NOSCRIPT(metaRefresh)); @@ -103,9 +103,8 @@ public void buildPage() throws DocFileIOException { bodyContent.add(HtmlTree.P(HtmlTree.A(targetPath, Text.of(targetPath)))); - var body = new HtmlTree(HtmlTag.BODY).setStyle(HtmlStyles.indexRedirectPage); - var main = HtmlTree.MAIN(bodyContent); - body.add(main); + var body = HtmlTree.BODY(HtmlStyles.indexRedirectPage) + .add(HtmlTree.MAIN(bodyContent)); HtmlDocument htmlDocument = new HtmlDocument( HtmlTree.HTML(configuration.getLocale().getLanguage(), head, body)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java index ecf1114364217..87d0fa95bf3c7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java @@ -224,7 +224,7 @@ protected void addElementDescription(IndexItem item, Content target) { default -> throw new Error(); } target.add(dt); - var dd = new HtmlTree(HtmlTag.DD); + var dd = HtmlTree.DD(); if (element.getKind() == ElementKind.MODULE || element.getKind() == ElementKind.PACKAGE) { addSummaryComment(element, dd); } else { @@ -261,7 +261,7 @@ protected void addTagDescription(IndexItem item, Content target) { dt.add(" - "); dt.add(contents.getContent("doclet.Search_tag_in", item.getHolder())); target.add(dt); - var dd = new HtmlTree(HtmlTag.DD); + var dd = HtmlTree.DD(); if (item.getDescription().isEmpty()) { dd.add(Entity.NO_BREAK_SPACE); } else { @@ -348,7 +348,7 @@ protected void addLinksForIndexes(List allFirstCharacters, Content co content.add(Entity.NO_BREAK_SPACE); } - content.add(new HtmlTree(HtmlTag.BR)); + content.add(HtmlTree.BR()); var pageLinks = Stream.of(IndexItem.Category.values()) .flatMap(c -> mainIndex.getItems(c).stream()) .filter(i -> !(i.isElementItem() || i.isTagItem())) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java index bd0ab2958d4e0..b688420681fd3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java @@ -194,7 +194,7 @@ protected void buildModuleDoc() throws DocletException { */ protected void buildContent() { Content moduleContent = getContentHeader(); - moduleContent.add(new HtmlTree(HtmlTag.HR)); + moduleContent.add(HtmlTree.HR()); Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); addModuleSignature(div); buildModuleDescription(div); @@ -825,7 +825,7 @@ public void addProvidesList(Table table) { } // Only display the implementation details in the "all" mode. if (moduleMode == ModuleMode.ALL && !implSet.isEmpty()) { - desc.add(new HtmlTree(HtmlTag.BR)); + desc.add(HtmlTree.BR()); desc.add("("); var implSpan = HtmlTree.SPAN(HtmlStyles.implementationLabel, contents.implementation); desc.add(implSpan); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 293a6453925f6..9d12d3bb23dcd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -516,14 +516,14 @@ public Content getContent() { } var navigationBar = HtmlTree.NAV(); - var navContent = new HtmlTree(HtmlTag.DIV); + var navContent = HtmlTree.DIV(HtmlStyles.navContent); Content skipNavLinks = contents.getContent("doclet.Skip_navigation_links"); String toggleNavLinks = configuration.getDocResources().getText("doclet.Toggle_navigation_links"); navigationBar.add(MarkerComments.START_OF_TOP_NAVBAR); // The mobile menu button uses three empty spans to produce its animated icon HtmlTree iconSpan = HtmlTree.SPAN(HtmlStyles.navBarToggleIcon).add(Entity.NO_BREAK_SPACE); - navContent.setStyle(HtmlStyles.navContent).add(HtmlTree.DIV(HtmlStyles.navMenuButton, - new HtmlTree(HtmlTag.BUTTON).setId(HtmlIds.NAVBAR_TOGGLE_BUTTON) + navContent.add(HtmlTree.DIV(HtmlStyles.navMenuButton, + HtmlTree.BUTTON(HtmlIds.NAVBAR_TOGGLE_BUTTON) .put(HtmlAttr.ARIA_CONTROLS, HtmlIds.NAVBAR_TOP.name()) .put(HtmlAttr.ARIA_EXPANDED, String.valueOf(false)) .put(HtmlAttr.ARIA_LABEL, toggleNavLinks) @@ -535,9 +535,7 @@ public Content getContent() { skipNavLinks.toString()))); Content aboutContent = userHeader; - var navList = new HtmlTree(HtmlTag.UL) - .setId(HtmlIds.NAVBAR_TOP_FIRSTROW) - .setStyle(HtmlStyles.navList) + var navList = HtmlTree.UL(HtmlIds.NAVBAR_TOP_FIRSTROW, HtmlStyles.navList) .put(HtmlAttr.TITLE, rowListTitle); addMainNavLinks(navList); navContent.add(navList); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java index b28b44d4cd3a6..078f5246de7f8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java @@ -204,7 +204,7 @@ private HtmlTree getBody() { HtmlTree body = getBody(getWindowTitle(title)); ContentBuilder headingContent = new ContentBuilder(); headingContent.add(contents.getContent("doclet.ClassUse_Title", packageText)); - headingContent.add(new HtmlTree(HtmlTag.BR)); + headingContent.add(HtmlTree.BR()); headingContent.add(name); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, headingContent); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java index ee022144fea57..d5683ec6e3c0a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java @@ -128,7 +128,7 @@ protected void buildPackageDoc() throws DocletException { */ protected void buildContent() { Content packageContent = getContentHeader(); - packageContent.add(new HtmlTree(HtmlTag.HR)); + packageContent.add(HtmlTree.HR()); Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); addPackageSignature(div); buildPackageDescription(div); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java index 0bd173df3d5f0..c30dae6bc65f6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java @@ -97,24 +97,21 @@ protected void addSearchFileContents(Content contentTree) { .add(HtmlTree.P(contents.getContent("doclet.search.browser_info"))) .add(HtmlTree.SPAN(Text.of("link")) .setId(HtmlId.of("page-search-link"))) - .add(new HtmlTree(HtmlTag.BUTTON) - .add(new HtmlTree(HtmlTag.IMG) + .add(HtmlTree.BUTTON(HtmlId.of("page-search-copy")) + .add(HtmlTree.of(HtmlTag.IMG) .put(HtmlAttr.SRC, pathToRoot.resolve(DocPaths.RESOURCE_FILES) .resolve(DocPaths.CLIPBOARD_SVG).getPath()) .put(HtmlAttr.ALT, copyUrlText)) .add(HtmlTree.SPAN(Text.of(copyText)) .put(HtmlAttr.DATA_COPIED, copiedText)) .addStyle(HtmlStyles.copy) - .put(HtmlAttr.ARIA_LABEL, copyUrlText) - .setId(HtmlId.of("page-search-copy"))) + .put(HtmlAttr.ARIA_LABEL, copyUrlText)) .add(HtmlTree.P(HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, HtmlId.of("search-redirect"))) .add(HtmlTree.LABEL("search-redirect", contents.getContent("doclet.search.redirect"))))) - .add(new HtmlTree(HtmlTag.P) - .setId(HtmlId.of("page-search-notify")) - .add(contents.getContent("doclet.search.loading"))) - .add(HtmlTree.DIV(new HtmlTree(HtmlTag.DIV) - .setId(HtmlId.of("result-container")) + .add(HtmlTree.P(contents.getContent("doclet.search.loading")) + .setId(HtmlId.of("page-search-notify"))) + .add(HtmlTree.DIV(HtmlTree.DIV(HtmlId.of("result-container")) .addUnchecked(Text.EMPTY)) .setId(HtmlId.of("result-section")) .put(HtmlAttr.STYLE, "display: none;") diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java index c3d1cc582f36a..ef9810f73749b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java @@ -58,7 +58,7 @@ protected Content getSerializableFieldsHeader() { } protected Content getFieldsContentHeader() { - return new HtmlTree(HtmlTag.LI).setStyle(HtmlStyles.blockList); + return HtmlTree.LI(HtmlStyles.blockList); } protected Content getSerializableFields(String heading, Content source) { @@ -76,12 +76,12 @@ protected void addMemberHeader(TypeMirror fieldType, String fieldName, Content c Content nameContent = Text.of(fieldName); var heading = HtmlTree.HEADING(Headings.SerializedForm.MEMBER_HEADING, nameContent); content.add(heading); - var pre = new HtmlTree(HtmlTag.PRE); Content fieldContent = writer.getLink(new HtmlLinkInfo( configuration, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, fieldType)); - pre.add(fieldContent); - pre.add(" "); - pre.add(fieldName); + var pre = HtmlTree.PRE() + .add(fieldContent) + .add(" ") + .add(fieldName); content.add(pre); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java index d9b888f2ee1b8..4ce7d662abbdb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java @@ -51,7 +51,7 @@ protected Content getSerializableMethodsHeader() { } protected Content getMethodsContentHeader() { - return new HtmlTree(HtmlTag.LI); + return HtmlTree.LI(); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java index 9059efcf81438..f1e26879ef44f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java @@ -569,7 +569,7 @@ private void appendParametersAndExceptions(Content target, int lastLineSeparator // empty parameters are added without packing target.add(parameters); } else { - target.add(new HtmlTree(HtmlTag.WBR)) + target.add(HtmlTree.WBR()) .add(HtmlTree.SPAN(HtmlStyles.parameters, parameters)); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java index 070b38421225b..aa20fc8c9aebc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java @@ -201,7 +201,7 @@ public void convertClass(TypeElement te, DocPath outputdir) .resolve(configuration.docPaths.forPackage(te)) .invert(); Content body = getHeader(); - var pre = new HtmlTree(HtmlTag.PRE); + var pre = HtmlTree.PRE(); try (var reader = new LineNumberReader(r)) { while ((line = reader.readLine()) != null) { addLineNo(pre, lineno); @@ -246,7 +246,7 @@ private void writeToFile(Content body, DocPath path, TypeElement te) throws DocF * @return the header content for the HTML file */ private static Content getHeader() { - return new HtmlTree(HtmlTag.BODY).setStyle(HtmlStyles.sourcePage); + return HtmlTree.BODY(HtmlStyles.sourcePage); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java index 5d09682d4920b..0e09920b7b158 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java @@ -361,7 +361,7 @@ public boolean write(Writer out, String newline, boolean atNewline) throws IOExc private Content toContent() { Content main; if (id != null) { - main = new HtmlTree(HtmlTag.DIV).setId(id); + main = HtmlTree.DIV(id); } else { main = new ContentBuilder(); } @@ -403,8 +403,7 @@ private Content toContent() { if (id == null) { throw new IllegalStateException("no id set for table"); } - var tabpanel = new HtmlTree(HtmlTag.DIV) - .setId(HtmlIds.forTabPanel(id)) + var tabpanel = HtmlTree.DIV(HtmlIds.forTabPanel(id)) .put(HtmlAttr.ROLE, "tabpanel") .put(HtmlAttr.ARIA_LABELLEDBY, defaultTabId.name()); table.add(getTableBody()); @@ -416,8 +415,7 @@ private Content toContent() { } private HtmlTree createTab(HtmlId tabId, HtmlStyle style, boolean defaultTab, Content tabLabel) { - var tab = new HtmlTree(HtmlTag.BUTTON) - .setId(tabId) + var tab = HtmlTree.BUTTON(tabId) .put(HtmlAttr.ROLE, "tab") .put(HtmlAttr.ARIA_SELECTED, defaultTab ? "true" : "false") .put(HtmlAttr.ARIA_CONTROLS, HtmlIds.forTabPanel(id).name()) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java index a9036d7dcd856..cfb8f7260d081 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java @@ -101,10 +101,10 @@ protected Content toContent(boolean hasFilterInput) { .put(HtmlAttr.VALUE, writer.resources.getText("doclet.filter_reset"))); } content.add(header); - content.add(new HtmlTree(HtmlTag.BUTTON).addStyle(HtmlStyles.hideSidebar) + content.add(HtmlTree.BUTTON(HtmlStyles.hideSidebar) .add(HtmlTree.SPAN(writer.contents.hideSidebar).add(Entity.NO_BREAK_SPACE)) .add(Entity.LEFT_POINTING_ANGLE)); - content.add(new HtmlTree(HtmlTag.BUTTON).addStyle(HtmlStyles.showSidebar) + content.add(HtmlTree.BUTTON(HtmlStyles.showSidebar) .add(Entity.RIGHT_POINTING_ANGLE) .add(HtmlTree.SPAN(Entity.NO_BREAK_SPACE).add(writer.contents.showSidebar))); return content.add(listBuilder); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 3d5b1a494ba2c..9b6b1c831b179 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -272,9 +272,9 @@ public boolean write(Writer out, String newline, boolean atNewline) throws IOExc * @return the HTML */ private Content toContent() { - var head = new HtmlTree(HtmlTag.HEAD); - head.add(getGeneratedBy(showTimestamp, generatedDate)); - head.add(HtmlTree.TITLE(title)); + var head = HtmlTree.of(HtmlTag.HEAD) + .add(getGeneratedBy(showTimestamp, generatedDate)) + .add(HtmlTree.TITLE(title)); head.add(HtmlTree.META("viewport", "width=device-width, initial-scale=1")); @@ -300,9 +300,9 @@ private Content toContent() { } if (canonicalLink != null) { - var link = new HtmlTree(HtmlTag.LINK); - link.put(HtmlAttr.REL, "canonical"); - link.put(HtmlAttr.HREF, canonicalLink.getPath()); + var link = HtmlTree.of(HtmlTag.LINK) + .put(HtmlAttr.REL, "canonical") + .put(HtmlAttr.HREF, canonicalLink.getPath()); head.add(link); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index af2378c0351d1..93f83c5ba90c1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -122,13 +122,13 @@ public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter tagl private Content snippetTagOutput(Element element, SnippetTree tag, StyledText content, String id, String lang) { var pathToRoot = tagletWriter.htmlWriter.pathToRoot; - var pre = new HtmlTree(HtmlTag.PRE).setStyle(HtmlStyles.snippet); + var pre = HtmlTree.PRE(HtmlStyles.snippet); if (id != null && !id.isBlank()) { pre.put(HtmlAttr.ID, id); } else { pre.put(HtmlAttr.ID, config.htmlIds.forSnippet(element, ids).name()); } - var code = new HtmlTree(HtmlTag.CODE) + var code = HtmlTree.CODE() .addUnchecked(Text.EMPTY); // Make sure the element is always rendered if (lang != null && !lang.isBlank()) { code.addStyle("language-" + lang); @@ -197,10 +197,10 @@ private Content snippetTagOutput(Element element, SnippetTree tag, StyledText co String copiedText = resources.getText("doclet.Copied_to_clipboard"); String copySnippetText = resources.getText("doclet.Copy_snippet_to_clipboard"); var snippetContainer = HtmlTree.DIV(HtmlStyles.snippetContainer, - new HtmlTree(HtmlTag.BUTTON) + HtmlTree.of(HtmlTag.BUTTON) .add(HtmlTree.SPAN(Text.of(copyText)) .put(HtmlAttr.DATA_COPIED, copiedText)) - .add(new HtmlTree(HtmlTag.IMG) + .add(HtmlTree.of(HtmlTag.IMG) .put(HtmlAttr.SRC, pathToRoot.resolve(DocPaths.RESOURCE_FILES) .resolve(DocPaths.CLIPBOARD_SVG).getPath()) .put(HtmlAttr.ALT, copySnippetText)) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java index f60537511746d..f1ca45cc0409c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java @@ -83,7 +83,17 @@ public class HtmlTree extends Content { * * @param tag the name */ - public HtmlTree(HtmlTag tag) { + public static HtmlTree of(HtmlTag tag) { + return new HtmlTree(tag); + } + + /** + * Creates an {@code HTMLTree} object representing an HTML element + * with the given name. + * + * @param tag the name + */ + HtmlTree(HtmlTag tag) { this.tag = Objects.requireNonNull(tag); } @@ -365,6 +375,46 @@ public static HtmlTree A(URI ref, Content body) { .add(body); } + /** + * Creates an HTML {@code BODY} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree BODY(HtmlStyle style) { + return new HtmlTree(HtmlTag.BODY) + .setStyle(style); + } + + private static final HtmlTree BR_INSTANCE = unmodifiableTree(HtmlTag.BR); + + /** + * {@return an HTML {@code BR} element} + */ + public static HtmlTree BR() { + return BR_INSTANCE; + } + + /** + * Creates an HTML {@code BUTTON} element with the given id. + * + * @param id the id + * @return the element + */ + public static HtmlTree BUTTON(HtmlId id) { + return new HtmlTree(HtmlTag.BUTTON).setId(id); + } + + /** + * Creates an HTML {@code BUTTON} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree BUTTON(HtmlStyle style) { + return new HtmlTree(HtmlTag.BUTTON).setStyle(style); + } + /** * Creates an HTML {@code CAPTION} element with the given content. * @@ -376,6 +426,15 @@ public static HtmlTree CAPTION(Content body) { .add(body); } + /** + * Creates an empty HTML {@code CODE} element. + * + * @return the element + */ + public static HtmlTree CODE() { + return new HtmlTree(HtmlTag.CODE); + } + /** * Creates an HTML {@code CODE} element with the given content. * @@ -387,6 +446,15 @@ public static HtmlTree CODE(Content body) { .add(body); } + /** + * Creates an empty HTML {@code DD} element. + * + * @return the element + */ + public static HtmlTree DD() { + return new HtmlTree(HtmlTag.DD); + } + /** * Creates an HTML {@code DD} element with the given content. * @@ -418,27 +486,14 @@ public static HtmlTree DETAILS(HtmlStyle style) { } /** - * Creates an HTML {@code DL} element with the given style. + * Creates an HTML {@code DIV} element with the given id. * - * @param style the style + * @param id the id * @return the element */ - public static HtmlTree DL(HtmlStyle style) { - return new HtmlTree(HtmlTag.DL) - .setStyle(style); - } - - /** - * Creates an HTML {@code DL} element with the given style and content. - * - * @param style the style - * @param body the content - * @return the element - */ - public static HtmlTree DL(HtmlStyle style, Content body) { - return new HtmlTree(HtmlTag.DL) - .setStyle(style) - .add(body); + public static HtmlTree DIV(HtmlId id) { + return new HtmlTree(HtmlTag.DIV) + .setId(id); } /** @@ -476,6 +531,30 @@ public static HtmlTree DIV(Content body) { .add(body); } + /** + * Creates an HTML {@code DL} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree DL(HtmlStyle style) { + return new HtmlTree(HtmlTag.DL) + .setStyle(style); + } + + /** + * Creates an HTML {@code DL} element with the given style and content. + * + * @param style the style + * @param body the content + * @return the element + */ + public static HtmlTree DL(HtmlStyle style, Content body) { + return new HtmlTree(HtmlTag.DL) + .setStyle(style) + .add(body); + } + /** * Creates an HTML {@code DT} element with the given content. * @@ -487,6 +566,17 @@ public static HtmlTree DT(Content body) { .add(body); } + /** + * Creates an HTML {@code EM} element with the given content. + * + * @param body content for the element + * @return the element + */ + public static HtmlTree EM(String body) { + return new HtmlTree(HtmlTag.EM) + .add(body); + } + /** * Creates an HTML {@code FOOTER} element. * The role is set to {@code contentinfo}. @@ -573,6 +663,15 @@ private static HtmlTag checkHeading(HtmlTag headingTag) { }; } + private static final HtmlTree HR_INSTANCE = unmodifiableTree(HtmlTag.HR); + + /** + * {@return an HTML {@code HR} element} + */ + public static HtmlTree HR() { + return HR_INSTANCE; + } + /** * Creates an HTML {@code HTML} element with the given {@code lang} attribute, * and {@code HEAD} and {@code BODY} contents. @@ -630,6 +729,27 @@ public static HtmlTree LABEL(String forLabel, Content body) { .add(body); } + /** + * Creates an empty HTML {@code LI} element. + * + * @return the element + */ + public static HtmlTree LI() { + return new HtmlTree(HtmlTag.LI); + } + + + /** + * Creates an HTML {@code LI} element with the given style. + * + * @param style the style + * @return the element + */ + public static HtmlTree LI(HtmlStyle style) { + return new HtmlTree(HtmlTag.LI) + .setStyle(style); + } + /** * Creates an HTML {@code LI} element with the given content. * @@ -776,6 +896,25 @@ public static HtmlTree P(HtmlStyle style, Content body) { .setStyle(style); } + /** + * Creates an empty HTML {@code PRE} element. + * + * @return the element + */ + public static HtmlTree PRE() { + return new HtmlTree(HtmlTag.PRE); + } + + /** + * Creates an HTML {@code PRE} element with the given style + * + * @param style the style + * @return the element + */ + public static HtmlTree PRE(HtmlStyle style) { + return new HtmlTree(HtmlTag.PRE).setStyle(style); + } + /** * Creates an HTML {@code PRE} element with some content. * @@ -971,6 +1110,15 @@ public static HtmlTree TITLE(String body) { .add(body); } + /** + * Creates an empty HTML {@code UL} element. + * + * @return the element + */ + public static HtmlTree UL() { + return new HtmlTree(HtmlTag.UL); + } + /** * Creates an HTML {@code UL} element with the given style. * @@ -982,6 +1130,19 @@ public static HtmlTree UL(HtmlStyle style) { .setStyle(style); } + /** + * Creates an HTML {@code UL} element with the given id and style. + * + * @param id the id + * @param style the style + * @return the element + */ + public static HtmlTree UL(HtmlId id, HtmlStyle style) { + return new HtmlTree(HtmlTag.UL) + .setId(id) + .setStyle(style); + } + /** * Creates an HTML {@code UL} element with the given style and some content. * @@ -1015,6 +1176,15 @@ public static HtmlTree UL(HtmlStyle style, Collection items, Function b ? 1L : 0L; + } + + @Test + @IR(applyIfPlatform = {"x64", "true"}, counts = {IRNode.X86_CMOVEL_IMM01U, "1"}, phase = CompilePhase.FINAL_CODE) + public static long testUnsigned(int a, int b) { + return Integer.compareUnsigned(a, b) > 0 ? 1L : 0L; + } + + @Test + @IR(applyIfPlatform = {"x64", "true"}, counts = {IRNode.X86_CMOVEL_IMM01UCF, "1"}, phase = CompilePhase.FINAL_CODE) + public static long testFloat(float a, float b) { + return a > b ? 1L : 0L; + } + + @DontCompile + public void assertResults(int a, int b) { + Asserts.assertEQ(a > b ? 1L : 0L, testSigned(a, b)); + Asserts.assertEQ(Integer.compareUnsigned(a, b) > 0 ? 1L : 0L, testUnsigned(a, b)); + Asserts.assertEQ((float) a > (float) b ? 1L : 0L, testFloat(a, b)); + } + + @Run(test = {"testSigned", "testUnsigned", "testFloat"}) + public void runMethod() { + assertResults(10, 20); + assertResults(20, 10); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 1b554df9e674d..162f384dc07b2 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2233,6 +2233,21 @@ public class IRNode { machOnlyNameRegex(X86_TESTL_REG, "testL_reg"); } + public static final String X86_CMOVEL_IMM01 = PREFIX + "X86_CMOVEL_IMM01" + POSTFIX; + static { + machOnlyNameRegex(X86_CMOVEL_IMM01, "cmovL_imm_01"); + } + + public static final String X86_CMOVEL_IMM01U = PREFIX + "X86_CMOVEL_IMM01U" + POSTFIX; + static { + machOnlyNameRegex(X86_CMOVEL_IMM01U, "cmovL_imm_01U"); + } + + public static final String X86_CMOVEL_IMM01UCF = PREFIX + "X86_CMOVEL_IMM01UCF" + POSTFIX; + static { + machOnlyNameRegex(X86_CMOVEL_IMM01UCF, "cmovL_imm_01UCF"); + } + /* * Utility methods to set up IR_NODE_MAPPINGS. */ diff --git a/test/hotspot/jtreg/compiler/loopopts/LongCountedLoopInInfiniteLoop.jasm b/test/hotspot/jtreg/compiler/loopopts/LongCountedLoopInInfiniteLoop.jasm new file mode 100644 index 0000000000000..e7f75d46b5b71 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/LongCountedLoopInInfiniteLoop.jasm @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +super public class LongCountedLoopInInfiniteLoop +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + Method test:"()V" + stack 3 locals 3 + { + // #1 = 0; + iconst_0; + istore_1; + + LOOPa: + // if #1 >= 10: goto END + iload_1; + bipush 10; + if_icmpge END; + + // if #1 > 1: goto LOOPc + iload_1; + iconst_1; + if_icmpgt LOOPc; + + // #2 = 0; + iconst_0; + istore_2; + + LOOPb: + // if #2 > 2: goto LOOPa + iload_2; + iconst_2; + if_icmpgt LOOPa; + + // #2 ++ + iinc 2, 1; + + goto LOOPb; + + LOOPc: + // #1 ++ + iinc 1, 1; + + goto LOOPa; + + END: + return; + + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/MoveStoreAfterInfiniteLoop.jasm b/test/hotspot/jtreg/compiler/loopopts/MoveStoreAfterInfiniteLoop.jasm new file mode 100644 index 0000000000000..f93a2aa1170d8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/MoveStoreAfterInfiniteLoop.jasm @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +super public class MoveStoreAfterInfiniteLoop +{ + static Field a:I; + static Field b:I; + static Field c:S; + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + +public static Method test:"()V" + stack 3 locals 3 + { + LTOP: + iconst_0; + istore_1; + + LOUTER: + iload_1; + bipush 10; + if_icmpge LTOP; + + getstatic Field c:"S"; + putstatic Field a:"I"; + + iconst_0; + istore_2; + + LINNER: + iload_2; + iconst_2; + if_icmpge LBOTTOM; + + getstatic Field b:"I"; + i2s; + putstatic Field c:"S"; + + iinc 2, 1; + + goto LINNER; + + LBOTTOM: + iinc 1, 1; + + goto LOUTER; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestLongCountedLoopInInfiniteLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestLongCountedLoopInInfiniteLoop.java new file mode 100644 index 0000000000000..4dc1679725811 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestLongCountedLoopInInfiniteLoop.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8336478 + * @summary C2: assert(!n->as_Loop()->is_loop_nest_inner_loop() || _loop_opts_cnt == 0) failed: should have been turned into a counted loop + * @compile LongCountedLoopInInfiniteLoop.jasm + * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xcomp -XX:PerMethodTrapLimit=0 -XX:PerMethodSpecTrapLimit=0 + * -XX:+IgnoreUnrecognizedVMOptions -XX:StressLongCountedLoop=2000000 + * -XX:CompileCommand=compileonly,TestLongCountedLoopInInfiniteLoop::test TestLongCountedLoopInInfiniteLoop + */ + +public class TestLongCountedLoopInInfiniteLoop { + public static void main(String[] args) { + LongCountedLoopInInfiniteLoop obj = new LongCountedLoopInInfiniteLoop(); + test(false, obj); + } + + private static void test(boolean flag, LongCountedLoopInInfiniteLoop obj) { + if (flag) { + obj.test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestMoveStoreAfterInfiniteLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestMoveStoreAfterInfiniteLoop.java new file mode 100644 index 0000000000000..322e7a5053c09 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestMoveStoreAfterInfiniteLoop.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338100 + * @summary C2: assert(!n_loop->is_member(get_loop(lca))) failed: control must not be back in the loop + * @compile MoveStoreAfterInfiniteLoop.jasm + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestMoveStoreAfterInfiniteLoop::test + * -XX:CompileCommand=inline,MoveStoreAfterInfiniteLoop::test TestMoveStoreAfterInfiniteLoop + */ + +public class TestMoveStoreAfterInfiniteLoop { + public static void main(String[] args) { + new MoveStoreAfterInfiniteLoop(); + test(false); + } + + private static void test(boolean flag) { + if (flag) { + MoveStoreAfterInfiniteLoop.test(); + } + } +} diff --git a/test/hotspot/jtreg/native_sanity/JniVersion.java b/test/hotspot/jtreg/native_sanity/JniVersion.java index 099ea547fca06..6459bcf7da1b8 100644 --- a/test/hotspot/jtreg/native_sanity/JniVersion.java +++ b/test/hotspot/jtreg/native_sanity/JniVersion.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 @@ -27,12 +27,12 @@ */ public class JniVersion { - public static final int JNI_VERSION_21 = 0x00150000; + public static final int JNI_VERSION_24 = 0x00180000; public static void main(String... args) throws Exception { System.loadLibrary("JniVersion"); int res = getJniVersion(); - if (res != JNI_VERSION_21) { + if (res != JNI_VERSION_24) { throw new Exception("Unexpected value returned from getJniVersion(): 0x" + Integer.toHexString(res)); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java index c814a9a406585..74ddfcebe1b24 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.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 @@ -76,6 +76,7 @@ public static void main(String[] args) throws Throwable { output.shouldContain(warningMessages[0]); output.shouldContain(warningMessages[1]); output.shouldContain("inside SimpleAgent"); + output.shouldContain("Skipping java/lang/invoke/BoundMethodHandle$Species_LLLL because it is dynamically generated"); // CDS dumping with a java agent with the AllowArchvingWithJavaAgent diagnostic option. output = TestCommon.testDump(appJar, TestCommon.list("Hello"), diff --git a/test/hotspot/jtreg/runtime/interpreter/LastJsrTest.java b/test/hotspot/jtreg/runtime/interpreter/LastJsrTest.java index 913a304ae38a3..fd9cffe002dab 100644 --- a/test/hotspot/jtreg/runtime/interpreter/LastJsrTest.java +++ b/test/hotspot/jtreg/runtime/interpreter/LastJsrTest.java @@ -23,18 +23,20 @@ /* * @test - * @bug 8335664 + * @bug 8335664 8338924 * @summary Ensure a program that ends with a JSR does not crash * @library /test/lib * @compile LastJsr.jasm * @compile LastJsrReachable.jasm - * @run main/othervm LastJsrTest + * @run main/othervm -Xbatch LastJsrTest */ public class LastJsrTest { public static void main(String[] args) { - LastJsr.test(); - LastJsrReachable.test(); + for (int i = 0; i < 1000; ++i) { + LastJsr.test(); + LastJsrReachable.test(); + } System.out.println("PASSED"); } } diff --git a/test/hotspot/jtreg/runtime/jni/checked/TestLargeUTF8Length.java b/test/hotspot/jtreg/runtime/jni/checked/TestLargeUTF8Length.java new file mode 100644 index 0000000000000..9186a7ea381bd --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/checked/TestLargeUTF8Length.java @@ -0,0 +1,73 @@ +/* + * 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 8328877 + * @summary Test warning for GetStringUTFLength and functionality of GetStringUTFLengthAsLong + * @requires vm.bits == 64 + * @library /test/lib + * @modules java.management + * @run main/native TestLargeUTF8Length launch + */ + +import java.util.Arrays; +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestLargeUTF8Length { + + static { + System.loadLibrary("TestLargeUTF8Length"); + } + + static native void checkUTF8Length(String s, long utf8Length); + + static void test() { + int length = Integer.MAX_VALUE/2 + 1; + char character = (char)0XD1; // N with tilde + long utf8Length = 2L * length; + char[] chrs = new char[length]; + Arrays.fill(chrs, character); + String s = new String(chrs); + checkUTF8Length(s, utf8Length); + } + + public static void main(String[] args) throws Throwable { + if (args == null || args.length == 0) { + test(); + return; + } + + OutputAnalyzer oa = ProcessTools.executeTestJava("-Xms9G", + "-Xmx9G", + "-Xcheck:jni", + "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, + "TestLargeUTF8Length"); + String warning = "WARNING: large String with modified UTF-8 length .*" + + "is reporting a reduced length of .* - use GetStringUTFLengthAsLong instead"; + oa.shouldHaveExitValue(0); + oa.stdoutShouldMatch(warning); + oa.reportDiagnosticSummary(); + } +} diff --git a/test/hotspot/jtreg/runtime/jni/checked/libTestLargeUTF8Length.c b/test/hotspot/jtreg/runtime/jni/checked/libTestLargeUTF8Length.c new file mode 100644 index 0000000000000..addf7d09d7ecc --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/checked/libTestLargeUTF8Length.c @@ -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. + */ + +#include + +#include +#include + +JNIEXPORT void JNICALL +Java_TestLargeUTF8Length_checkUTF8Length(JNIEnv *env, jclass clz, + jstring str, jlong expected_length) { + + jlong utf8_length; + + // First get truncated length to generate warning + utf8_length = (*env)->GetStringUTFLength(env, str); + + if (utf8_length != INT_MAX - 1) { + printf("Error: expected length of %d, but got %lld\n", INT_MAX - 1, + (long long) utf8_length); + (*env)->FatalError(env, "Unexpected truncated length"); + } + + // Now get true length + utf8_length = (*env)->GetStringUTFLengthAsLong(env, str); + + if (utf8_length != expected_length ) { + printf("Error: expected length of %lld, but got %lld\n", + (long long) expected_length, (long long) utf8_length); + (*env)->FatalError(env, "Unexpected true length"); + } + + +} diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 697fe82187ca3..47a2e13b460cf 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -470,9 +470,6 @@ sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java java/awt/Window/8159168/SetShapeTest.java 8274106 macosx-aarch64 java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java 8274106 macosx-aarch64 -# This test fails on macOS 14 -java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java 8324782 macosx-all - # Wayland related java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java 8280991 linux-x64 diff --git a/test/jdk/java/awt/Choice/SelectCurrentItemTest/SelectCurrentItemTest.java b/test/jdk/java/awt/Choice/SelectCurrentItemTest/SelectCurrentItemTest.java deleted file mode 100644 index 3d3f8c807938a..0000000000000 --- a/test/jdk/java/awt/Choice/SelectCurrentItemTest/SelectCurrentItemTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/* - @test - @bug 4902933 8197810 - @summary Test that selecting the current item doesnot send an ItemEvent - @key headful - @run main SelectCurrentItemTest -*/ - -import java.awt.Choice; -import java.awt.Robot; -import java.awt.Frame; -import java.awt.BorderLayout; -import java.awt.AWTException; -import java.awt.Point; -import java.awt.Dimension; -import java.awt.event.InputEvent; -import java.awt.event.ItemListener; -import java.awt.event.WindowListener; -import java.awt.event.ItemEvent; -import java.awt.event.WindowEvent; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class SelectCurrentItemTest implements ItemListener, WindowListener { - //Declare things used in the test, like buttons and labels here - private Frame frame; - private Choice theChoice; - private Robot robot; - - private CountDownLatch latch = new CountDownLatch(1); - private volatile boolean passed = true; - - private void init() - { - try { - robot = new Robot(); - robot.setAutoDelay(500); - } catch (AWTException e) { - throw new RuntimeException("Unable to create Robot. Test fails."); - } - - frame = new Frame("SelectCurrentItemTest"); - frame.setLayout(new BorderLayout()); - theChoice = new Choice(); - for (int i = 0; i < 10; i++) { - theChoice.add(new String("Choice Item " + i)); - } - theChoice.addItemListener(this); - frame.add(theChoice); - frame.addWindowListener(this); - - frame.setLocation(1,20); - robot.mouseMove(10, 30); - frame.pack(); - frame.setVisible(true); - } - - public static void main(String... args) { - SelectCurrentItemTest test = new SelectCurrentItemTest(); - test.init(); - try { - test.latch.await(12000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) {} - test.robot.waitForIdle(); - - try { - if (!test.passed) { - throw new RuntimeException("TEST FAILED."); - } - } finally { - test.frame.dispose(); - } - } - - private void run() { - try {Thread.sleep(1000);} catch (InterruptedException e){} - // get loc of Choice on screen - Point loc = theChoice.getLocationOnScreen(); - // get bounds of Choice - Dimension size = theChoice.getSize(); - robot.mouseMove(loc.x + size.width - 10, loc.y + size.height / 2); - - robot.setAutoDelay(250); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - - robot.delay(1000); - - robot.mouseMove(loc.x + size.width / 2, loc.y + size.height); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - robot.waitForIdle(); - latch.countDown(); - } - - @Override public void itemStateChanged(ItemEvent e) { - System.out.println("ItemEvent received. Test fails"); - passed = false; - } - - @Override public void windowOpened(WindowEvent e) { - System.out.println("windowActivated()"); - (new Thread(this::run)).start(); - } - - @Override public void windowActivated(WindowEvent e) {} - @Override public void windowDeactivated(WindowEvent e) {} - @Override public void windowClosed(WindowEvent e) {} - @Override public void windowClosing(WindowEvent e) {} - @Override public void windowIconified(WindowEvent e) {} - @Override public void windowDeiconified(WindowEvent e) {} -} diff --git a/test/jdk/java/awt/Choice/SelectItem/SelectCurrentItemTest.java b/test/jdk/java/awt/Choice/SelectItem/SelectCurrentItemTest.java new file mode 100644 index 0000000000000..9bfcfeb9a97bc --- /dev/null +++ b/test/jdk/java/awt/Choice/SelectItem/SelectCurrentItemTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2002, 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.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +/* + * @test + * @bug 4902933 8197810 + * @summary Test that selecting the current item does not send an ItemEvent + * @key headful + * @run main SelectCurrentItemTest +*/ +public class SelectCurrentItemTest + extends WindowAdapter + implements ItemListener { + private static Frame frame; + private static Choice choice; + + private final Robot robot; + + private final CountDownLatch windowOpened = new CountDownLatch(1); + private final CountDownLatch mouseClicked = new CountDownLatch(1); + + protected final CountDownLatch itemStateChanged = new CountDownLatch(1); + + protected SelectCurrentItemTest() throws AWTException { + robot = new Robot(); + robot.setAutoDelay(250); + } + + private void createUI() { + frame = new Frame(getClass().getName()); + frame.setLayout(new BorderLayout()); + + choice = new Choice(); + for (int i = 0; i < 10; i++) { + choice.add("Choice Item " + i); + } + choice.addItemListener(this); + choice.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + System.out.println("mouseClicked()"); + mouseClicked.countDown(); + } + }); + + frame.add(choice, BorderLayout.CENTER); + + frame.addWindowListener(this); + + frame.setLocationRelativeTo(null); + frame.setResizable(false); + frame.pack(); + frame.setVisible(true); + } + + protected final void runTest() + throws InterruptedException, InvocationTargetException { + try { + doTest(); + } finally { + EventQueue.invokeAndWait(this::dispose); + } + } + + private void doTest() + throws InterruptedException, InvocationTargetException { + EventQueue.invokeAndWait(this::createUI); + + if (!windowOpened.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("Frame is not open in time"); + } + robot.waitForIdle(); + + final int initialIndex = getSelectedIndex(); + + final Rectangle choiceRect = getChoiceRect(); + + // Open the choice popup + robot.mouseMove(choiceRect.x + choiceRect.width - 10, + choiceRect.y + choiceRect.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (!mouseClicked.await(500, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("Mouse is not clicked in time"); + } + robot.waitForIdle(); + + // Click an item in the choice popup + final Point pt = getClickLocation(choiceRect); + robot.mouseMove(pt.x, pt.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.waitForIdle(); + + checkItemStateChanged(); + + final int currentIndex = getSelectedIndex(); + System.out.println("initialIndex = " + initialIndex); + System.out.println("currentIndex = " + currentIndex); + checkSelectedIndex(initialIndex, currentIndex); + } + + protected void checkItemStateChanged() throws InterruptedException { + if (itemStateChanged.await(500, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("ItemEvent is received but unexpected"); + } + } + + protected void checkSelectedIndex(final int initialIndex, + final int currentIndex) { + if (initialIndex != currentIndex) { + throw new RuntimeException("Selected index in Choice should not change"); + } + } + + /** + * {@return the location for clicking choice popup to select an item} + * @param choiceRect the bounds of the Choice component + */ + protected Point getClickLocation(final Rectangle choiceRect) { + // Click on the first item in the popup, it's the selected item + return new Point(choiceRect.x + choiceRect.width / 2, + choiceRect.y + choiceRect.height + 3); + } + + private int getSelectedIndex() + throws InterruptedException, InvocationTargetException { + AtomicInteger index = new AtomicInteger(); + EventQueue.invokeAndWait(() -> index.set(choice.getSelectedIndex())); + return index.get(); + } + + private Rectangle getChoiceRect() + throws InterruptedException, InvocationTargetException { + AtomicReference rect = new AtomicReference<>(); + EventQueue.invokeAndWait( + () -> rect.set(new Rectangle(choice.getLocationOnScreen(), + choice.getSize()))); + return rect.get(); + } + + public static void main(String... args) throws Exception { + new SelectCurrentItemTest().runTest(); + } + + private void dispose() { + if (frame != null) { + frame.dispose(); + } + } + + @Override + public final void itemStateChanged(ItemEvent e) { + System.out.println("itemStateChanged: " + e); + itemStateChanged.countDown(); + } + + @Override + public final void windowOpened(WindowEvent e) { + System.out.println("windowActivated()"); + windowOpened.countDown(); + } + +} diff --git a/test/jdk/java/awt/Choice/SelectItem/SelectNewItemTest.java b/test/jdk/java/awt/Choice/SelectItem/SelectNewItemTest.java new file mode 100644 index 0000000000000..1dba3fd905b66 --- /dev/null +++ b/test/jdk/java/awt/Choice/SelectItem/SelectNewItemTest.java @@ -0,0 +1,69 @@ +/* + * 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 + * 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.awt.AWTException; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.concurrent.TimeUnit; + +/* + * @test + * @bug 8215921 + * @summary Test that selecting a different item does send an ItemEvent + * @key headful + * @run main SelectNewItemTest +*/ +public final class SelectNewItemTest + extends SelectCurrentItemTest { + + private SelectNewItemTest() throws AWTException { + super(); + } + + @Override + protected void checkItemStateChanged() throws InterruptedException { + if (!itemStateChanged.await(500, TimeUnit.MILLISECONDS)) { + throw new RuntimeException("ItemEvent is not received"); + } + } + + @Override + protected void checkSelectedIndex(final int initialIndex, + final int currentIndex) { + if (initialIndex == currentIndex) { + throw new RuntimeException("Selected index in Choice should've changed"); + } + } + + @Override + protected Point getClickLocation(final Rectangle choiceRect) { + // Click a different item the popup, not the first one + return new Point(choiceRect.x + choiceRect.width / 2, + choiceRect.y + choiceRect.height * 3); + } + + public static void main(String... args) throws Exception { + new SelectNewItemTest().runTest(); + } + +} diff --git a/test/jdk/java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java b/test/jdk/java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java deleted file mode 100644 index 502c5a161dff4..0000000000000 --- a/test/jdk/java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 8215921 - @summary Test that selecting a different item does send an ItemEvent - @key headful - @run main SelectNewItemTest -*/ - -import java.awt.Choice; -import java.awt.Robot; -import java.awt.Frame; -import java.awt.BorderLayout; -import java.awt.AWTException; -import java.awt.Point; -import java.awt.Dimension; -import java.awt.event.InputEvent; -import java.awt.event.ItemListener; -import java.awt.event.WindowListener; -import java.awt.event.ItemEvent; -import java.awt.event.WindowEvent; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class SelectNewItemTest implements ItemListener, WindowListener { - //Declare things used in the test, like buttons and labels here - private Frame frame; - private Choice theChoice; - private Robot robot; - - private CountDownLatch latch = new CountDownLatch(1); - private volatile boolean passed = false; - - private void init() - { - try { - robot = new Robot(); - robot.setAutoDelay(500); - } catch (AWTException e) { - throw new RuntimeException("Unable to create Robot. Test fails."); - } - - frame = new Frame("SelectNewItemTest"); - frame.setLayout(new BorderLayout()); - theChoice = new Choice(); - for (int i = 0; i < 10; i++) { - theChoice.add(new String("Choice Item " + i)); - } - theChoice.addItemListener(this); - frame.add(theChoice); - frame.addWindowListener(this); - - frame.setLocation(1,20); - frame.setSize(200, 50); - robot.mouseMove(10, 30); - frame.pack(); - frame.setVisible(true); - } - - public static void main(String... args) { - SelectNewItemTest test = new SelectNewItemTest(); - test.init(); - try { - test.latch.await(12000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) {} - test.robot.waitForIdle(); - - try { - if (!test.passed) { - throw new RuntimeException("TEST FAILED."); - } - } finally { - test.frame.dispose(); - } - } - - private void run() { - try { - Thread.sleep(1000); - - Point loc = theChoice.getLocationOnScreen(); - int selectedIndex = theChoice.getSelectedIndex(); - Dimension size = theChoice.getSize(); - - robot.mouseMove(loc.x + size.width - 10, loc.y + size.height / 2); - - robot.setAutoDelay(250); - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - - robot.delay(1000); - - //make sure that the mouse moves to a different item, so that - //itemStateChanged is called. - robot.mouseMove(loc.x + size.width / 2, loc.y + 3 * size.height); - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - robot.waitForIdle(); - - if (selectedIndex == theChoice.getSelectedIndex()) - throw new RuntimeException("Test case failed - expected to select" + - " a different item than " + selectedIndex); - - selectedIndex = theChoice.getSelectedIndex(); - //now click on the same item and make sure that item event is - //not generated. - robot.delay(1000); - robot.mouseMove(loc.x + size.width - 10, loc.y + size.height / 2); - - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - //Make sure that the popup menu scrolls back to show the index from - //beginning, so that the second mouse click happens on the previously - //selected item. - //For example, on windows, it automatically scrolls the list to show - //the currently selected item just below the choice, which can - //throw off the test. - if (System.getProperty("os.name").toLowerCase().startsWith("win")) { - robot.mouseWheel(-100); - } - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - - robot.delay(1000); - robot.mouseMove(loc.x + size.width / 2, loc.y + 3 * size.height); - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - robot.waitForIdle(); - - if (selectedIndex != theChoice.getSelectedIndex()) - throw new RuntimeException("Test failed. Expected to select the same item " + - "located at: " + selectedIndex + " but got an item selected at: " + theChoice.getSelectedIndex()); - } catch(InterruptedException e) { - throw new RuntimeException(e.getCause()); - } finally { - latch.countDown(); - } - } - - @Override public void itemStateChanged(ItemEvent e) { - if (!passed) { - System.out.println("ItemEvent received. Test passes"); - passed = true; - } else { - System.out.println("ItemEvent received for second click. Test fails"); - passed = false; - } - } - - @Override public void windowOpened(WindowEvent e) { - System.out.println("windowActivated()"); - (new Thread(this::run)).start(); - } - - @Override public void windowActivated(WindowEvent e) {} - @Override public void windowDeactivated(WindowEvent e) {} - @Override public void windowClosed(WindowEvent e) {} - @Override public void windowClosing(WindowEvent e) {} - @Override public void windowIconified(WindowEvent e) {} - @Override public void windowDeiconified(WindowEvent e) {} -} diff --git a/test/jdk/java/foreign/TestMappedHandshake.java b/test/jdk/java/foreign/TestMappedHandshake.java new file mode 100644 index 0000000000000..46fb4fb45fb9d --- /dev/null +++ b/test/jdk/java/foreign/TestMappedHandshake.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @requires vm.flavor != "zero" + * @modules java.base/jdk.internal.vm.annotation java.base/jdk.internal.misc + * @key randomness + * @run testng/othervm TestMappedHandshake + * @run testng/othervm -Xint TestMappedHandshake + * @run testng/othervm -XX:TieredStopAtLevel=1 TestMappedHandshake + * @run testng/othervm -XX:-TieredCompilation TestMappedHandshake + */ + +import java.io.File; +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +public class TestMappedHandshake { + + static final int SEGMENT_SIZE = 1_000_000; + static final int ACCESS_START_DELAY_MILLIS = 100; + static final int POST_ACCESS_DELAY_MILLIS = 1; + static final int TIMED_RUN_TIME_SECONDS = 10; + static final int MAX_EXECUTOR_WAIT_SECONDS = 20; + + static final int NUM_ACCESSORS = 5; + + static final Path tempPath; + + static { + try { + File file = File.createTempFile("buffer", "txt"); + file.deleteOnExit(); + tempPath = file.toPath(); + Files.write(file.toPath(), new byte[SEGMENT_SIZE], StandardOpenOption.WRITE); + + } catch (IOException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + @Test + public void testHandshake() throws InterruptedException, IOException { + try (FileChannel fileChannel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE) ; + Arena arena = Arena.ofShared()) { + MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, SEGMENT_SIZE, arena); + ExecutorService accessExecutor = Executors.newFixedThreadPool(NUM_ACCESSORS + 1); + // start handshaker + accessExecutor.execute(new Handshaker()); + Thread.sleep(ACCESS_START_DELAY_MILLIS); + // start accessors + for (int i = 0 ; i < NUM_ACCESSORS ; i++) { + accessExecutor.execute(new MappedSegmentAccessor(segment)); + } + + accessExecutor.shutdown(); + assertTrue(accessExecutor.awaitTermination(MAX_EXECUTOR_WAIT_SECONDS, TimeUnit.SECONDS)); + } + } + + static abstract class TimedAction implements Runnable { + @Override + public void run() { + long start = System.currentTimeMillis(); + while (true) { + try { + doAction(); + } catch (Throwable ex) { + // ignore + } finally { + long elapsed = System.currentTimeMillis() - start; + if (elapsed > TIMED_RUN_TIME_SECONDS * 1000) { + break; + } + } + } + } + + abstract void doAction() throws Throwable; + } + + static class MappedSegmentAccessor extends TimedAction { + + final MemorySegment segment; + + MappedSegmentAccessor(MemorySegment segment) { + this.segment = segment; + } + + @Override + void doAction() throws Throwable { + segment.load(); + Thread.sleep(POST_ACCESS_DELAY_MILLIS); + segment.isLoaded(); + Thread.sleep(POST_ACCESS_DELAY_MILLIS); + segment.unload(); + Thread.sleep(POST_ACCESS_DELAY_MILLIS); + segment.force(); + } + } + + static class Handshaker extends TimedAction { + + @Override + public void doAction() { + Arena.ofShared().close(); + } + } +} diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java index 88636bf5420ce..9a4500b2f5a1a 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; -import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; import java.util.ArrayList; @@ -76,6 +75,94 @@ public void testByteCopy(SegmentKind kind1, SegmentKind kind2) { } } + @Test(dataProvider = "conjunctSegments") + public void testCopy5ArgInvariants(MemorySegment src, MemorySegment dst) { + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, 0, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, -1, dst, 0, src.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, -1, src.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 1, dst, 0, src.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> MemorySegment.copy(src, 0, dst, 1, src.byteSize())); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy7ArgRight(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 0, dst, 1, CopyOp.of7Arg()); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy5ArgRight(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 0, dst, 1, CopyOp.of5Arg()); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy7ArgLeft(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 1, dst, 0, CopyOp.of7Arg()); + } + + @Test(dataProvider = "conjunctSegments") + public void testConjunctCopy5ArgLeft(MemorySegment src, MemorySegment dst) { + testConjunctCopy(src, 1, dst, 0, CopyOp.of5Arg()); + } + + void testConjunctCopy(MemorySegment src, long srcOffset, MemorySegment dst, long dstOffset, CopyOp op) { + if (src.byteSize() < 4 || src.address() != dst.address()) { + // Only test larger segments where the skew is zero + return; + } + + try (var arena = Arena.ofConfined()) { + // Create a disjoint segment for expected behavior + MemorySegment disjoint = arena.allocate(dst.byteSize()); + disjoint.copyFrom(src); + op.copy(src, srcOffset, disjoint, dstOffset, 3); + byte[] expected = disjoint.toArray(JAVA_BYTE); + + // Do a conjoint copy + op.copy(src, srcOffset, dst, dstOffset, 3); + byte[] actual = dst.toArray(JAVA_BYTE); + + assertEquals(actual, expected); + } + } + + @FunctionalInterface + interface CopyOp { + void copy(MemorySegment src, long srcOffset, MemorySegment dst, long dstOffset, long bytes); + + static CopyOp of5Arg() { + return MemorySegment::copy; + } + + static CopyOp of7Arg() { + return (MemorySegment src, long srcOffset, MemorySegment dst, long dstOffset, long bytes) -> + MemorySegment.copy(src, JAVA_BYTE, srcOffset, dst, JAVA_BYTE, dstOffset, bytes); + } + + } + + @Test(dataProvider = "segmentKinds") + public void testByteCopySizes(SegmentKind kind1, SegmentKind kind2) { + + record Offsets(int src, int dst){} + + for (Offsets offsets : List.of(new Offsets(3, 7), new Offsets(7, 3))) { + for (int size = 0; size < 513; size++) { + MemorySegment src = kind1.makeSegment(size + offsets.src()); + MemorySegment dst = kind2.makeSegment(size + offsets.dst()); + //prepare source slice + for (int i = 0; i < size; i++) { + src.set(JAVA_BYTE, i + offsets.src(), (byte) i); + } + //perform copy + MemorySegment.copy(src, offsets.src(), dst, offsets.dst(), size); + //check that copy actually worked + for (int i = 0; i < size; i++) { + assertEquals(dst.get(JAVA_BYTE, i + offsets.dst()), (byte) i); + } + } + } + } + @Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "segmentKinds") public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) { MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE); @@ -277,6 +364,28 @@ static Object[][] segmentKinds() { return cases.toArray(Object[][]::new); } + @DataProvider + static Object[][] conjunctSegments() { + List cases = new ArrayList<>(); + for (SegmentKind kind : SegmentKind.values()) { + // Different paths might be taken in the implementation depending on the + // size, type, and address of the underlying segments. + for (int len : new int[]{0, 1, 7, 512}) { + for (int offset : new int[]{-1, 0, 1}) { + MemorySegment segment = kind.makeSegment(len + 2); + MemorySegment src = segment.asSlice(1 + offset, len); + MemorySegment dst = segment.asSlice(1, len); + for (int i = 0; i < len; i++) { + src.set(JAVA_BYTE, i, (byte) i); + } + // src = 0, 1, ... , len-1 + cases.add(new Object[]{src, dst}); + } + } + } + return cases.toArray(Object[][]::new); + } + @DataProvider static Object[][] types() { return Arrays.stream(Type.values()) diff --git a/test/jdk/java/io/File/GetCanonicalPath.java b/test/jdk/java/io/File/GetCanonicalPath.java index e54227e44b46e..d69e90fbbfc87 100644 --- a/test/jdk/java/io/File/GetCanonicalPath.java +++ b/test/jdk/java/io/File/GetCanonicalPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,17 +22,21 @@ */ /* @test - * @bug 4899022 + * @bug 4899022 8003887 * @summary Look for erroneous representation of drive letter * @run junit GetCanonicalPath */ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -122,4 +126,88 @@ void driveLetter() throws IOException { String path = new File("c:/").getCanonicalPath(); assertFalse(path.length() > 3, "Drive letter incorrectly represented"); } + + // Create a File with the given pathname and return the File as a Path + private static Path createFile(String pathname) throws IOException { + File file = new File(pathname); + file.deleteOnExit(); + return file.toPath(); + } + + private static boolean supportsLinks = true; + private static String linkMessage; + + private static Path link; + private static Path sublink; + private static Path subsub; + + @BeforeAll + static void createSymlinks() throws IOException { + final String DIR = "dir"; + final String SUBDIR = "subdir"; + final String TARGET = "target.txt"; + final String LINK = "link"; + final String SUBLINK = "sublink"; + final String FILE = "file.txt"; + + // Create directories dir/subdir + Path dir = createFile(DIR); + Path subdir = createFile(dir.resolve(SUBDIR).toString()); + Files.createDirectories(subdir); + + // Create file dir/subdir/target.txt + Path target = createFile(subdir.resolve(TARGET).toString()); + Files.createFile(target); + + // Create symbolic link link -> dir + link = createFile(Path.of(LINK).toString()); + try { + Files.createSymbolicLink(link, dir); + } catch (UnsupportedOperationException | IOException x) { + if (OS.WINDOWS.isCurrentOs()) { + supportsLinks = false; + linkMessage = "\"" + x.getMessage() + "\""; + return; + } else { + throw x; + } + } + + sublink = createFile(Path.of(DIR, SUBDIR, SUBLINK).toString()); + Path file = createFile(Path.of(DIR, SUBDIR, FILE).toString()); + Files.createFile(file); + + // Create symbolic link dir/subdir/sublink -> file.txt + Files.createSymbolicLink(sublink, Path.of(FILE)); + sublink.toFile().deleteOnExit(); + + subsub = createFile(Path.of(LINK, SUBDIR, SUBLINK).toString()); + } + + @Test + void linkToDir() throws IOException { + Assumptions.assumeTrue(supportsLinks, linkMessage); + + // Check link evaluates to dir + assertEquals(link.toRealPath().toString(), + link.toFile().getCanonicalPath()); + } + + @Test + void linkToFile() throws IOException { + Assumptions.assumeTrue(supportsLinks, linkMessage); + + // Check sublink evaluates to file.txt + assertEquals(sublink.toRealPath().toString(), + sublink.toFile().getCanonicalPath()); + } + + @Test + void linkToFileInSubdir() throws IOException { + Assumptions.assumeTrue(supportsLinks, linkMessage); + + // Check link/subdir/sublink evaluates to dir/subdir/file.txt + assertEquals(subsub.toRealPath().toString(), + subsub.toFile().getCanonicalPath()); + } } diff --git a/test/jdk/java/lang/String/CountNonZeroAscii.java b/test/jdk/java/lang/String/CountNonZeroAscii.java new file mode 100644 index 0000000000000..d4b8a4fb1ebb4 --- /dev/null +++ b/test/jdk/java/lang/String/CountNonZeroAscii.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/* + * @test + * @modules java.base/jdk.internal.access + * @summary test latin1 String countNonZeroAscii + * @run main/othervm -XX:+CompactStrings CountNonZeroAscii + * @run main/othervm -XX:-CompactStrings CountNonZeroAscii + */ +public class CountNonZeroAscii { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + public static void main(String [] args) { + byte[] bytes = new byte[1000]; + + Arrays.fill(bytes, (byte) 'A'); + String s = new String(bytes, StandardCharsets.ISO_8859_1); + assertEquals(bytes.length, JLA.countNonZeroAscii(s)); + + for (int i = 0; i < bytes.length; i++) { + for (int j = Byte.MIN_VALUE; j <= 0; j++) { + bytes[i] = (byte) j; + s = new String(bytes, StandardCharsets.ISO_8859_1); + assertEquals(i, JLA.countNonZeroAscii(s)); + } + bytes[i] = (byte) 'A'; + } + } + + static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new AssertionError("Expected " + expected + " but got " + actual); + } + } +} diff --git a/test/jdk/java/util/List/ListDefaults.java b/test/jdk/java/util/List/ListDefaults.java index c29d2243f414b..8c9e7e3f613cf 100644 --- a/test/jdk/java/util/List/ListDefaults.java +++ b/test/jdk/java/util/List/ListDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, 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 @@ -50,7 +50,7 @@ /** * @test * @summary Unit tests for extension methods on List - * @bug 8023367 8037106 + * @bug 8023367 8037106 8325679 * @library ../Collection/testlibrary * @build CollectionAsserts CollectionSupplier ExtendsAbstractList * @run testng ListDefaults diff --git a/test/jdk/javax/swing/JButton/SwingButtonResizeTestWithOpenGL.java b/test/jdk/javax/swing/JButton/SwingButtonResizeTestWithOpenGL.java index 96ef9edc57100..5b21c07f71e35 100644 --- a/test/jdk/javax/swing/JButton/SwingButtonResizeTestWithOpenGL.java +++ b/test/jdk/javax/swing/JButton/SwingButtonResizeTestWithOpenGL.java @@ -99,6 +99,7 @@ private void createGUI() { frame.setLocation(200, 200); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); button.setPreferredSize(new Dimension(300, 300)); + button.setFocusPainted(false); button.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent fe) { focusGainedLatch.countDown(); @@ -124,9 +125,8 @@ public void runTest() throws Exception { try { robot = new Robot(); - robot.setAutoWaitForIdle(true); - robot.setAutoDelay(200); - + robot.waitForIdle(); + robot.delay(1000); if (focusGainedLatch.await(3, TimeUnit.SECONDS)) { System.out.println("Button focus gained..."); } else { @@ -142,17 +142,18 @@ public void runTest() throws Exception { // some platforms may not support maximize frame if (frame.getToolkit().isFrameStateSupported( JFrame.MAXIMIZED_BOTH)) { - robot.waitForIdle(); // maximize frame from normal size frame.setExtendedState(JFrame.MAXIMIZED_BOTH); System.out.println("Frame is maximized"); robot.waitForIdle(); + robot.delay(100); if (frame.getToolkit().isFrameStateSupported(JFrame.NORMAL)) { System.out.println("Frame is back to normal"); // resize from maximum size to normal frame.setExtendedState(JFrame.NORMAL); - + robot.waitForIdle(); + robot.delay(100); // capture image of JButton after resize System.out.println( "Getting image of JButton after resize..image2"); @@ -209,9 +210,8 @@ private BufferedImage getButtonImage() { } private void disposeFrame() { - if (frame != null) { + if(frame != null) { frame.dispose(); - frame = null; } } diff --git a/test/jdk/jdk/jfr/api/event/TestGetDuration.java b/test/jdk/jdk/jfr/api/event/TestGetDuration.java index c3242ea90c7ee..b25969198edad 100644 --- a/test/jdk/jdk/jfr/api/event/TestGetDuration.java +++ b/test/jdk/jdk/jfr/api/event/TestGetDuration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ private static void verifyCustomEvents() throws Exception { Events.hasEvents(testEvents); for (RecordedEvent re : testEvents) { int id = re.getValue("id"); - Asserts.assertEquals(re.getDuration(), Duration.between(re.getStartTime(), re.getEndTime())); + Asserts.assertEquals(re.getDuration(), re.getStartTime().until(re.getEndTime())); switch (id) { case DURATIONAL_EVENT_ID: Asserts.assertTrue(!re.getDuration().isNegative() && !re.getDuration().isZero()); @@ -111,7 +111,7 @@ private static void verifyNativeEvents() throws Exception { List recordedEvents = Events.fromRecording(r); Events.hasEvents(recordedEvents); for (RecordedEvent re : recordedEvents) { - Asserts.assertEquals(re.getDuration(), Duration.between(re.getStartTime(), re.getEndTime())); + Asserts.assertEquals(re.getDuration(), re.getStartTime().until(re.getEndTime())); switch (re.getEventType().getName()) { case EventNames.JVMInformation: Asserts.assertTrue(re.getDuration().isZero()); diff --git a/test/jdk/jdk/jfr/api/recording/misc/TestGetStream.java b/test/jdk/jdk/jfr/api/recording/misc/TestGetStream.java index dd936101caa9e..3b353d0968be8 100644 --- a/test/jdk/jdk/jfr/api/recording/misc/TestGetStream.java +++ b/test/jdk/jdk/jfr/api/recording/misc/TestGetStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ public static void main(String[] args) throws Exception { } private static void printTimeStamp(String name, Instant t) { - Duration s = Duration.between(offset, t); + Duration s = offset.until(t); System.out.println(name + ": " + (s.getSeconds() * 1_000_000_000L + s.getNano())); } diff --git a/test/jdk/jdk/jfr/api/recording/options/TestDuration.java b/test/jdk/jdk/jfr/api/recording/options/TestDuration.java index 6a2ef2c30cda1..8f231ab77a038 100644 --- a/test/jdk/jdk/jfr/api/recording/options/TestDuration.java +++ b/test/jdk/jdk/jfr/api/recording/options/TestDuration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ public static void main(String[] args) throws Throwable { Instant afterStop = Instant.now(); Asserts.assertLessThanOrEqual(r.getStopTime(), afterStop, "getStopTime() > afterStop"); - long durationMillis = Duration.between(afterStart, r.getStopTime()).toMillis(); + long durationMillis = afterStart.until(r.getStopTime()).toMillis(); // Performance of test servers varies too much to make a strict check of actual duration. // We only check that recording stops before timeout of 20 seconds. diff --git a/test/jdk/jdk/jfr/api/recording/state/TestStateDuration.java b/test/jdk/jdk/jfr/api/recording/state/TestStateDuration.java index bdf620fa1b394..5e8ef60b36720 100644 --- a/test/jdk/jdk/jfr/api/recording/state/TestStateDuration.java +++ b/test/jdk/jdk/jfr/api/recording/state/TestStateDuration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ public static void main(String[] args) throws Throwable { System.out.println("Waiting for recording to reach STOPPED state"); CommonHelper.waitForRecordingState(r, RecordingState.STOPPED); Instant stop = Instant.now(); - Duration measuredDuration = Duration.between(start, stop); + Duration measuredDuration = start.until(stop); System.out.println("Recording stopped at " + stop + ". Measured duration " + measuredDuration); // Timer task uses System.currentMillis, and java.time uses other source. Duration deltaDueToClockNotInSync = Duration.ofMillis(100); diff --git a/test/jdk/jdk/jfr/api/recording/state/TestStateScheduleStart.java b/test/jdk/jdk/jfr/api/recording/state/TestStateScheduleStart.java index ddeee64a7b4dd..3708ded56f167 100644 --- a/test/jdk/jdk/jfr/api/recording/state/TestStateScheduleStart.java +++ b/test/jdk/jdk/jfr/api/recording/state/TestStateScheduleStart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ public static void main(String[] args) throws Throwable { // Test servers vary too much in performance to make an accurate check. // We only check that we don't time out after 20 seconds. Instant started = Instant.now(); - long millis = Duration.between(start, started).toMillis(); + long millis = start.until(started).toMillis(); System.out.println("Recording started at " + started + ". Delta millis=" + millis + ", expected about 2000"); verifyIllegalState(() -> r.start(), "double start()"); diff --git a/test/jdk/jdk/jfr/event/runtime/TestThreadCpuTimeEvent.java b/test/jdk/jdk/jfr/event/runtime/TestThreadCpuTimeEvent.java index a3ebb1550dbd9..a6520614eab85 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestThreadCpuTimeEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestThreadCpuTimeEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,7 @@ public void run() { barrier.await(); Instant start = Instant.now(); counter = 0; - while ((Duration.between(start, Instant.now()).compareTo(runTime) < 0) || + while ((start.until(Instant.now()).compareTo(runTime) < 0) || (counter < cpuConsumerMinCount)) { counter++; } diff --git a/test/jdk/sun/security/tools/keytool/TestImportPass.java b/test/jdk/sun/security/tools/keytool/TestImportPass.java new file mode 100644 index 0000000000000..adf8dba841555 --- /dev/null +++ b/test/jdk/sun/security/tools/keytool/TestImportPass.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8339347 + * @summary Test keytool -importpass with password input from System.in for + * the non-terminal console + * @library /test/lib + * @run main TestImportPass + */ + +import jdk.test.lib.SecurityTools; + +public class TestImportPass { + public static void main(String[] args) throws Throwable { + SecurityTools.setResponse("pass123"); + SecurityTools.keytool("-importpass -keystore ks.p12 -storepass changeit " + + "-storetype pkcs12 -alias newentry") + .shouldNotContain("Enter the password to be stored:") + .shouldHaveExitValue(0); + + SecurityTools.keytool("-list -keystore ks.p12 -storepass changeit " + + "-v") + .shouldContain("Alias name: newentry") + .shouldHaveExitValue(0); + } +} diff --git a/test/jdk/sun/security/validator/samedn.sh b/test/jdk/sun/security/validator/samedn.sh index 6a30b14715721..a38d6e7099003 100644 --- a/test/jdk/sun/security/validator/samedn.sh +++ b/test/jdk/sun/security/validator/samedn.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -62,10 +62,11 @@ $KT -genkeypair -alias ca1 -dname CN=CA -keyalg rsa -sigalg md5withrsa -ext bc - $KT -genkeypair -alias ca2 -dname CN=CA -keyalg rsa -sigalg sha1withrsa -ext bc -startdate -1y $KT -genkeypair -alias user -dname CN=User -keyalg rsa -# 2. Signing: ca -> user +# 2. Signing: ca -> user. The startdate is set to 1 minute in the past to ensure the certificate +# is valid at the time of validation and to prevent any issues with timing discrepancies -$KT -certreq -alias user | $KT -gencert -rfc -alias ca1 > samedn1.certs -$KT -certreq -alias user | $KT -gencert -rfc -alias ca2 > samedn2.certs +$KT -certreq -alias user | $KT -gencert -rfc -alias ca1 -startdate -1M > samedn1.certs +$KT -certreq -alias user | $KT -gencert -rfc -alias ca2 -startdate -1M > samedn2.certs # 3. Append the ca file diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java index 9a9b20541c8b6..03adf00ca736c 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java @@ -70,19 +70,19 @@ public void test() { // Generate the HTML output using the HTML document generation within doclet. public static String generateHtmlTree() { // Document type for the HTML document - HtmlTree html = new HtmlTree(HtmlTag.HTML); - HtmlTree head = new HtmlTree(HtmlTag.HEAD); - HtmlTree title = new HtmlTree(HtmlTag.TITLE); + HtmlTree html = HtmlTree.of(HtmlTag.HTML); + HtmlTree head = HtmlTree.of(HtmlTag.HEAD); + HtmlTree title = HtmlTree.of(HtmlTag.TITLE); // String content within the document TextBuilder titleContent = new TextBuilder("Markup test"); title.add(titleContent); head.add(title); // Test META tag - HtmlTree meta = new HtmlTree(HtmlTag.META); + HtmlTree meta = HtmlTree.of(HtmlTag.META); meta.put(HtmlAttr.NAME, "keywords"); meta.put(HtmlAttr.CONTENT, "testContent"); head.add(meta); - HtmlTree link = new HtmlTree(HtmlTag.LINK); + HtmlTree link = HtmlTree.of(HtmlTag.LINK); link.put(HtmlAttr.REL, "testRel"); link.put(HtmlAttr.HREF, "testLink.html"); head.add(link); @@ -90,10 +90,10 @@ public static String generateHtmlTree() { // Comment within the document Comment bodyMarker = new Comment("======== START OF BODY ========"); html.add(bodyMarker); - HtmlTree body = new HtmlTree(HtmlTag.BODY); + HtmlTree body = HtmlTree.of(HtmlTag.BODY); Comment pMarker = new Comment("======== START OF PARAGRAPH ========"); body.add(pMarker); - HtmlTree p = new HtmlTree(HtmlTag.P); + HtmlTree p = HtmlTree.of(HtmlTag.P); TextBuilder bodyContent = new TextBuilder( "This document is generated from sample source code and HTML " + "files with examples of a wide variety of Java language constructs: packages, " + @@ -106,24 +106,24 @@ public static String generateHtmlTree() { TextBuilder pContent = new TextBuilder(" to out a link."); p.add(pContent); body.add(p); - HtmlTree p1 = new HtmlTree(HtmlTag.P); + HtmlTree p1 = HtmlTree.of(HtmlTag.P); // Test another version of A tag. - HtmlTree anchor = new HtmlTree(HtmlTag.A); + HtmlTree anchor = HtmlTree.of(HtmlTag.A); anchor.put(HtmlAttr.HREF, "testLink.html"); anchor.put(HtmlAttr.ID, "Another version of a tag"); p1.add(anchor); body.add(p1); // Test for empty tags. - HtmlTree dl = new HtmlTree(HtmlTag.DL); + HtmlTree dl = HtmlTree.of(HtmlTag.DL); html.add(dl); // Test for empty nested tags. - HtmlTree dlTree = new HtmlTree(HtmlTag.DL); - dlTree.add(new HtmlTree(HtmlTag.DT)); - dlTree.add(new HtmlTree (HtmlTag.DD)); + HtmlTree dlTree = HtmlTree.of(HtmlTag.DL); + dlTree.add(HtmlTree.of(HtmlTag.DT)); + dlTree.add(HtmlTree.of (HtmlTag.DD)); html.add(dlTree); - HtmlTree dlDisplay = new HtmlTree(HtmlTag.DL); - dlDisplay.add(new HtmlTree(HtmlTag.DT)); - HtmlTree dd = new HtmlTree (HtmlTag.DD); + HtmlTree dlDisplay = HtmlTree.of(HtmlTag.DL); + dlDisplay.add(HtmlTree.of(HtmlTag.DT)); + HtmlTree dd = HtmlTree.of (HtmlTag.DD); TextBuilder ddContent = new TextBuilder("Test DD"); dd.add(ddContent); dlDisplay.add(dd); @@ -132,7 +132,7 @@ public static String generateHtmlTree() { body.add(emptyString); Comment emptyComment = new Comment(""); body.add(emptyComment); - HtmlTree hr = new HtmlTree(HtmlTag.HR); + HtmlTree hr = HtmlTree.of(HtmlTag.HR); body.add(hr); html.add(body); HtmlDocument htmlDoc = new HtmlDocument(html); diff --git a/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java b/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java index bd44fe8814119..518ecebd70488 100644 --- a/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java +++ b/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java @@ -55,7 +55,7 @@ public static void main(String[] args) { } private static void check(HtmlTag htmlTag) { - boolean elementIsVoid = new HtmlTree(htmlTag).isVoid(); + boolean elementIsVoid = HtmlTree.of(htmlTag).isVoid(); boolean elementHasNoEndTag = htmlTag.endKind == HtmlTag.EndKind.NONE; if (elementIsVoid != elementHasNoEndTag) { throw new AssertionError(htmlTag + ", " + elementIsVoid + ", " + elementHasNoEndTag); diff --git a/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java b/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java new file mode 100644 index 0000000000000..a124b0792688a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/classfile/Utf8EntryWriteTo.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.classfile; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.*; +import java.lang.constant.*; +import java.nio.charset.StandardCharsets; +import java.util.HexFormat; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.*; + +import jdk.internal.classfile.impl.*; +/** + * Test various operations on + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 1, time = 2) +@Measurement(iterations = 3, time = 1) +@Fork(jvmArgsAppend = "--enable-preview", value = 3) +@State(Scope.Thread) +public class Utf8EntryWriteTo { + static final ClassDesc STRING_BUILDER = ClassDesc.ofDescriptor("Ljava/lang/StringBuilder;"); + static final MethodTypeDesc MTD_append = MethodTypeDesc.of(STRING_BUILDER, CD_String); + static final MethodTypeDesc MTD_String = MethodTypeDesc.of(CD_String); + static final ClassDesc CLASS_DESC = ClassDesc.ofDescriptor("Lorg/openjdk/bench/java/lang/classfile/String$$StringConcat;"); + + @Param({"ascii", "utf8_2_bytes", "utf8_3_bytes", "emoji"}) + public String charType; + ConstantPoolBuilder poolBuilder; + ClassEntry thisClass; + + @Setup + public void setup() throws Exception { + byte[] bytes = HexFormat.of().parseHex( + switch (charType) { + case "ascii" -> "78"; + case "utf8_2_bytes" -> "c2a9"; + case "utf8_3_bytes" -> "e6b8a9"; + case "emoji" -> "e29da3efb88f"; + default -> throw new IllegalArgumentException("bad charType: " + charType); + } + ); + String s = new String(bytes, 0, bytes.length, StandardCharsets.UTF_8); + String[] constants = new String[128]; + for (int i = 0; i < constants.length; i++) { + constants[i] = "A".repeat(i).concat(s); + } + + poolBuilder = ConstantPoolBuilder.of(); + thisClass = poolBuilder.classEntry(CLASS_DESC); + for (var c : constants) { + poolBuilder.utf8Entry(c); + } + } + + @Benchmark + public void writeTo(Blackhole bh) { + bh.consume(ClassFile + .of() + .build(thisClass, poolBuilder, (ClassBuilder clb) -> {})); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CopyTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/CopyTest.java new file mode 100644 index 0000000000000..8996b1de11742 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CopyTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.bench.java.lang.foreign; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.ByteBuffer; +import java.util.concurrent.TimeUnit; + +import static java.lang.foreign.ValueLayout.*; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3) +public class CopyTest { + + @Param({"0", "1", "2", "3", "4", "5", "6", "7", "8", + "9", "10", "11", "12", "13", "14", "15", "16", + "17", "18", "19", "20", "21", "22", "23", "24", + "25", "26", "27", "28", "29", "30", "31", "32", + "33", "36", "40", "44", "48", "52", "56", "60", "63", "64", "128"}) + public int ELEM_SIZE; + + byte[] srcArray; + byte[] dstArray; + MemorySegment heapSrcSegment; + MemorySegment heapDstSegment; + MemorySegment nativeSrcSegment; + MemorySegment nativeDstSegment; + ByteBuffer srcBuffer; + ByteBuffer dstBuffer; + + @Setup + public void setup() { + srcArray = new byte[ELEM_SIZE]; + dstArray = new byte[ELEM_SIZE]; + heapSrcSegment = MemorySegment.ofArray(srcArray); + heapDstSegment = MemorySegment.ofArray(dstArray); + nativeSrcSegment = Arena.ofAuto().allocate(ELEM_SIZE); + nativeDstSegment = Arena.ofAuto().allocate(ELEM_SIZE); + srcBuffer = ByteBuffer.wrap(srcArray); + dstBuffer = ByteBuffer.wrap(dstArray); + } + + @Benchmark + public void array_copy() { + System.arraycopy(srcArray, 0, dstArray, 0, ELEM_SIZE); + } + + @Benchmark + public void heap_segment_copy5Arg() { + MemorySegment.copy(heapSrcSegment, 0, heapDstSegment, 0, ELEM_SIZE); + } + + @Benchmark + public void native_segment_copy5Arg() { + MemorySegment.copy(nativeSrcSegment, 0, nativeDstSegment, 0, ELEM_SIZE); + } + + @Benchmark + public void heap_segment_copy7arg() { + MemorySegment.copy(heapSrcSegment, JAVA_BYTE, 0, heapDstSegment, JAVA_BYTE, 0, ELEM_SIZE); + } + + @Benchmark + public void buffer_copy() { + dstBuffer.put(srcBuffer); + } + +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java b/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java index 35a346d3ed8b8..4b04e168f162e 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java +++ b/test/micro/org/openjdk/bench/vm/compiler/x86/BasicRules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; +import java.util.Random; + @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) @@ -38,6 +40,16 @@ public class BasicRules { static final int INT_IMM = 100; static final long LONG_IMM = 100; + @Setup(Level.Iteration) + public void setup() { + Random random = new Random(1000); + + for (int i = 0; i < 1024; i++) { + INT_ARRAY[i] = random.nextInt(); + LONG_ARRAY[i] = random.nextLong(); + } + } + @Benchmark public void andL_rReg_imm255(Blackhole bh) { for (int i = 0; i < LONG_ARRAY.length; i++) { @@ -125,5 +137,12 @@ public void subL_rReg_imm(Blackhole bh) { bh.consume(LONG_ARRAY[i] - LONG_IMM); } } + + @Benchmark + public void cmovL_imm_01(Blackhole bh) { + for (int i = 0; i < INT_ARRAY.length; i++) { + bh.consume(INT_ARRAY[i] > 0 ? 1L : 0L); + } + } }