diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index f3fa19ddb31e0..f6dd20db3d67f 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -79,7 +79,7 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox assert(LockingMode != LM_MONITOR, "LM_MONITOR is already handled, by emit_lock()"); if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(Roop, Rmark, tmp, slow_case); + lightweight_lock(Rbox, Roop, Rmark, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { NearLabel done; diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp index 3641d82dabea9..025ef4c8915cd 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp @@ -34,12 +34,12 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register temp1, Register temp2) { - compiler_fast_lock_lightweight_object(obj, temp1, temp2); + compiler_fast_lock_lightweight_object(obj, box, temp1, temp2); } void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register temp1, Register temp2) { - compiler_fast_unlock_lightweight_object(obj, temp1, temp2); + compiler_fast_unlock_lightweight_object(obj, box, temp1, temp2); } //------------------------------------------------------ diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp index 383a32448745c..85ddc5bf18548 100644 --- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp @@ -36,8 +36,8 @@ #define __ _masm-> -static const int native_invoker_code_base_size = 512; -static const int native_invoker_size_per_args = 8; +static const int native_invoker_code_base_size = 384; +static const int native_invoker_size_per_args = 12; RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature, int num_args, diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index e56beaa9f569c..d00b6c3e2cc2e 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1012,7 +1012,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(object, header, tmp, slow_case); + lightweight_lock(monitor, object, header, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { // Load markWord from object into header. diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 65a7d3abe90af..6c26e17d5ce3b 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -6007,10 +6007,10 @@ SkipIfEqual::~SkipIfEqual() { // - obj: the object to be locked, contents preserved. // - temp1, temp2: temporary registers, contents destroyed. // Note: make sure Z_R1 is not manipulated here when C2 compiler is in play -void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register temp2, Label& slow) { +void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register temp1, Register temp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, temp1, temp2); + assert_different_registers(basic_lock, obj, temp1, temp2); Label push; const Register top = temp1; @@ -6022,6 +6022,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register tem // instruction emitted as it is part of C1's null check semantics. z_lg(mark, Address(obj, mark_offset)); + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))); + z_mvghi(om_cache_addr, 0); + } // First we need to check if the lock-stack has room for pushing the object reference. z_lgf(top, Address(Z_thread, ls_top_offset)); @@ -6145,8 +6150,8 @@ void MacroAssembler::lightweight_unlock(Register obj, Register temp1, Register t bind(unlocked); } -void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2) { - assert_different_registers(obj, tmp1, tmp2); +void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2) { + assert_different_registers(obj, box, tmp1, tmp2); // Handle inflated monitor. NearLabel inflated; @@ -6155,6 +6160,11 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe // Finish fast lock unsuccessfully. MUST branch to with flag == EQ NearLabel slow_path; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); + } + if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp1, obj); z_tm(Address(tmp1, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); @@ -6219,33 +6229,77 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe { // Handle inflated monitor. bind(inflated); + const Register tmp1_monitor = tmp1; if (!UseObjectMonitorTable) { - // mark contains the tagged ObjectMonitor*. - const Register tagged_monitor = mark; - const Register zero = tmp2; - - // Try to CAS m->owner from null to current thread. - // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. - // Otherwise, register zero is filled with the current owner. - z_lghi(zero, 0); - z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); - z_bre(locked); - - // Check if recursive. - z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction - z_brne(slow_path); - - // Recursive - z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); - z_cgr(zero, zero); - // z_bru(locked); - // Uncomment above line in the future, for now jump address is right next to us. + assert(tmp1_monitor == mark, "should be the same here"); } else { - // OMCache lookup not supported yet. Take the slowpath. - // Set flag to NE - z_ltgr(obj, obj); + NearLabel monitor_found; + + // load cache address + z_la(tmp1, Address(Z_thread, JavaThread::om_cache_oops_offset())); + + const int num_unrolled = 2; + for (int i = 0; i < num_unrolled; i++) { + z_cg(obj, Address(tmp1)); + z_bre(monitor_found); + add2reg(tmp1, in_bytes(OMCache::oop_to_oop_difference())); + } + + NearLabel loop; + // Search for obj in cache + + bind(loop); + + // check for match. + z_cg(obj, Address(tmp1)); + z_bre(monitor_found); + + // search until null encountered, guaranteed _null_sentinel at end. + add2reg(tmp1, in_bytes(OMCache::oop_to_oop_difference())); + z_cghsi(0, tmp1, 0); + z_brne(loop); // if not EQ to 0, go for another loop + + // we reached to the end, cache miss + z_ltgr(obj, obj); // set CC to NE z_bru(slow_path); + + // cache hit + bind(monitor_found); + z_lg(tmp1_monitor, Address(tmp1, OMCache::oop_to_monitor_difference())); } + NearLabel monitor_locked; + // lock the monitor + + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const Register zero = tmp2; + + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag); + const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag); + + + // Try to CAS m->owner from null to current thread. + // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. + // Otherwise, register zero is filled with the current owner. + z_lghi(zero, 0); + z_csg(zero, Z_thread, owner_address); + z_bre(monitor_locked); + + // Check if recursive. + z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction + z_brne(slow_path); + + // Recursive + z_agsi(recursions_address, 1ll); + + bind(monitor_locked); + if (UseObjectMonitorTable) { + // Cache the monitor for unlock + z_stg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + } + // set the CC now + z_cgr(obj, obj); } BLOCK_COMMENT("} handle_inflated_monitor_lightweight_locking"); @@ -6270,11 +6324,11 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe // C2 uses the value of flag (NE vs EQ) to determine the continuation. } -void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2) { - assert_different_registers(obj, tmp1, tmp2); +void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2) { + assert_different_registers(obj, box, tmp1, tmp2); // Handle inflated monitor. - NearLabel inflated, inflated_load_monitor; + NearLabel inflated, inflated_load_mark; // Finish fast unlock successfully. MUST reach to with flag == EQ. NearLabel unlocked; // Finish fast unlock unsuccessfully. MUST branch to with flag == NE. @@ -6294,7 +6348,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis z_aghi(top, -oopSize); z_cg(obj, Address(Z_thread, top)); - branch_optimized(bcondNotEqual, inflated_load_monitor); + branch_optimized(bcondNotEqual, inflated_load_mark); // Pop lock-stack. #ifdef ASSERT @@ -6315,6 +6369,9 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis // Not recursive // Check for monitor (0b10). + // Because we got here by popping (meaning we pushed in locked) + // there will be no monitor in the box. So we need to push back the obj + // so that the runtime can fix any potential anonymous owner. z_lg(mark, Address(obj, mark_offset)); z_tmll(mark, markWord::monitor_value); if (!UseObjectMonitorTable) { @@ -6353,7 +6410,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis { // Handle inflated monitor. - bind(inflated_load_monitor); + bind(inflated_load_mark); z_lg(mark, Address(obj, mark_offset)); @@ -6378,49 +6435,61 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis bind(check_done); #endif // ASSERT + const Register tmp1_monitor = tmp1; + if (!UseObjectMonitorTable) { - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; + assert(tmp1_monitor == mark, "should be the same here"); + } else { + // Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack. + z_lg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + // null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*) + z_cghi(tmp1_monitor, alignof(ObjectMonitor*)); - NearLabel not_recursive; - const Register recursions = tmp2; + z_brl(slow_path); + } - // Check if recursive. - load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - z_bre(not_recursive); // if 0 then jump, it's not recursive locking + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; - // Recursive unlock - z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); - z_cgr(monitor, monitor); // set the CC to EQUAL - z_bru(unlocked); + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag}; + const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag}; + const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag}; + const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag}; - bind(not_recursive); + NearLabel not_recursive; + const Register recursions = tmp2; - NearLabel not_ok; - // Check if the entry lists are empty. - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - z_brne(not_ok); - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - z_brne(not_ok); + // Check if recursive. + load_and_test_long(recursions, recursions_address); + z_bre(not_recursive); // if 0 then jump, it's not recursive locking - z_release(); - z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + // Recursive unlock + z_agsi(recursions_address, -1ll); + z_cgr(monitor, monitor); // set the CC to EQUAL + z_bru(unlocked); - z_bru(unlocked); // CC = EQ here + bind(not_recursive); - bind(not_ok); + NearLabel not_ok; + // Check if the entry lists are empty. + load_and_test_long(tmp2, EntryList_address); + z_brne(not_ok); + load_and_test_long(tmp2, cxq_address); + z_brne(not_ok); - // The owner may be anonymous, and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); - z_bru(slow_path); // CC = NE here - } else { - // OMCache lookup not supported yet. Take the slowpath. - // Set flag to NE - z_ltgr(obj, obj); - z_bru(slow_path); - } + z_release(); + z_stg(tmp2 /*=0*/, owner_address); + + z_bru(unlocked); // CC = EQ here + + bind(not_ok); + + // The owner may be anonymous, and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + z_stg(Z_thread, owner_address); + z_bru(slow_path); // CC = NE here } bind(unlocked); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index c380f4dec1029..5d3a4c2994091 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -752,10 +752,10 @@ class MacroAssembler: public Assembler { void compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2); void compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2); - void lightweight_lock(Register obj, Register tmp1, Register tmp2, Label& slow); + void lightweight_lock(Register basic_lock, Register obj, Register tmp1, Register tmp2, Label& slow); void lightweight_unlock(Register obj, Register tmp1, Register tmp2, Label& slow); - void compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2); - void compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2); + void compiler_fast_lock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2); + void compiler_fast_unlock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2); void resolve_jobject(Register value, Register tmp1, Register tmp2); void resolve_global_jobject(Register value, Register tmp1, Register tmp2); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 9954c78ce1efa..65c94db09dcc8 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1713,7 +1713,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for locking. if (LockingMode == LM_LIGHTWEIGHT) { // Fast_lock kills r_temp_1, r_temp_2. - __ compiler_fast_lock_lightweight_object(r_oop, r_tmp1, r_tmp2); + __ compiler_fast_lock_lightweight_object(r_oop, r_box, r_tmp1, r_tmp2); } else { // Fast_lock kills r_temp_1, r_temp_2. __ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2); @@ -1917,7 +1917,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for unlocking. if (LockingMode == LM_LIGHTWEIGHT) { // Fast_unlock kills r_tmp1, r_tmp2. - __ compiler_fast_unlock_lightweight_object(r_oop, r_tmp1, r_tmp2); + __ compiler_fast_unlock_lightweight_object(r_oop, r_box, r_tmp1, r_tmp2); } else { // Fast_unlock kills r_tmp1, r_tmp2. __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 079c8199b1870..f142e306a6b02 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -83,6 +83,7 @@ void CompiledICData::initialize(CallInfo* call_info, Klass* receiver_klass) { _speculated_klass = (uintptr_t)receiver_klass; } if (call_info->call_kind() == CallInfo::itable_call) { + assert(call_info->resolved_method() != nullptr, "virtual or interface method must be found"); _itable_defc_klass = call_info->resolved_method()->method_holder(); _itable_refc_klass = call_info->resolved_klass(); } @@ -238,6 +239,7 @@ void CompiledIC::set_to_megamorphic(CallInfo* call_info) { return; } #ifdef ASSERT + assert(call_info->resolved_method() != nullptr, "virtual or interface method must be found"); int index = call_info->resolved_method()->itable_index(); assert(index == itable_index, "CallInfo pre-computes this"); InstanceKlass* k = call_info->resolved_method()->method_holder(); @@ -254,6 +256,7 @@ void CompiledIC::set_to_megamorphic(CallInfo* call_info) { } } + assert(call_info->selected_method() != nullptr, "virtual or interface method must be found"); log_trace(inlinecache)("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT, p2i(_call->instruction_address()), call_info->selected_method()->print_value_string(), p2i(entry)); diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index cadc3e8a2e802..36847580d9c63 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -87,7 +87,7 @@ void CallInfo::set_interface(Klass* resolved_klass, // we should pick the vtable index from the resolved method. // In that case, the caller must call set_virtual instead of set_interface. assert(resolved_method->method_holder()->is_interface(), ""); - assert(itable_index == resolved_method()->itable_index(), ""); + assert(itable_index == resolved_method->itable_index(), ""); set_common(resolved_klass, resolved_method, selected_method, CallInfo::itable_call, itable_index, CHECK); } @@ -1541,7 +1541,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, } // resolve the method in the receiver class, unless it is private - if (!is_abstract_interpretation && !resolved_method()->is_private()) { + if (!is_abstract_interpretation && !resolved_method->is_private()) { // do lookup based on receiver klass // This search must match the linktime preparation search for itable initialization // to correctly enforce loader constraints for interface method inheritance. @@ -1590,17 +1590,17 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, assert(is_abstract_interpretation || vtable_index == selected_method->vtable_index(), "sanity check"); result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK); } else if (resolved_method->has_itable_index()) { - int itable_index = resolved_method()->itable_index(); + int itable_index = resolved_method->itable_index(); log_develop_trace(itables)(" -- itable index: %d", itable_index); result.set_interface(resolved_klass, resolved_method, selected_method, itable_index, CHECK); } else { int index = resolved_method->vtable_index(); log_develop_trace(itables)(" -- non itable/vtable index: %d", index); assert(index == Method::nonvirtual_vtable_index, "Oops hit another case!"); - assert(resolved_method()->is_private() || - (resolved_method()->is_final() && resolved_method->method_holder() == vmClasses::Object_klass()), + assert(resolved_method->is_private() || + (resolved_method->is_final() && resolved_method->method_holder() == vmClasses::Object_klass()), "Should only have non-virtual invokeinterface for private or final-Object methods!"); - assert(resolved_method()->can_be_statically_bound(), "Should only have non-virtual invokeinterface for statically bound methods!"); + assert(resolved_method->can_be_statically_bound(), "Should only have non-virtual invokeinterface for statically bound methods!"); // This sets up the nonvirtual form of "virtual" call (as needed for final and private methods) result.set_virtual(resolved_klass, resolved_method, resolved_method, index, CHECK); } diff --git a/src/hotspot/share/interpreter/linkResolver.hpp b/src/hotspot/share/interpreter/linkResolver.hpp index 340c7d412d599..69bdf56137d41 100644 --- a/src/hotspot/share/interpreter/linkResolver.hpp +++ b/src/hotspot/share/interpreter/linkResolver.hpp @@ -99,7 +99,6 @@ class CallInfo : public StackObj { // Materialize a java.lang.invoke.ResolvedMethodName for this resolved_method void set_resolved_method_name(TRAPS); - BasicType result_type() const { return selected_method()->result_type(); } CallKind call_kind() const { return _call_kind; } int vtable_index() const { // Even for interface calls the vtable index could be non-negative. diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 817a35959f348..321d8add75594 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -604,6 +604,7 @@ void ConstantPoolCache::adjust_method_entries(bool * trace_name_printed) { if (old_method == nullptr || !old_method->is_old()) { continue; } + assert(!old_method->is_deleted(), "cannot delete these methods"); Method* new_method = old_method->get_new_method(); resolved_indy_entry_at(j)->adjust_method_entry(new_method); log_adjust("indy", old_method, new_method, trace_name_printed); diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index 1f3bf15a8769d..30abd575da46a 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -39,7 +39,7 @@ inline void BasicLock::set_displaced_header(markWord header) { inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); -#if defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) +#if defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390) return reinterpret_cast(get_metadata()); #else // Other platforms do not make use of the cache yet, diff --git a/src/java.base/share/classes/java/io/DataInputStream.java b/src/java.base/share/classes/java/io/DataInputStream.java index eab7a6e2f189a..59377aca429ca 100644 --- a/src/java.base/share/classes/java/io/DataInputStream.java +++ b/src/java.base/share/classes/java/io/DataInputStream.java @@ -1,5 +1,6 @@ /* * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +26,11 @@ package java.io; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.util.ByteArray; +import java.nio.charset.StandardCharsets; import java.util.Objects; /** @@ -45,6 +49,7 @@ * @since 1.0 */ public class DataInputStream extends FilterInputStream implements DataInput { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; private static final char[] EMPTY_CHAR_ARRAY = new char[0]; @@ -573,18 +578,16 @@ public final String readUTF() throws IOException { */ public static final String readUTF(DataInput in) throws IOException { int utflen = in.readUnsignedShort(); - byte[] bytearr; - char[] chararr; + byte[] bytearr = null; if (in instanceof DataInputStream dis) { - if (dis.bytearr.length < utflen) { - dis.bytearr = new byte[utflen*2]; - dis.chararr = new char[utflen*2]; + if (dis.bytearr.length >= utflen) { + bytearr = dis.bytearr; } - chararr = dis.chararr; - bytearr = dis.bytearr; - } else { + } + boolean trusted = false; + if (bytearr == null) { bytearr = new byte[utflen]; - chararr = new char[utflen]; + trusted = true; } int c, char2, char3; @@ -592,12 +595,35 @@ public static final String readUTF(DataInput in) throws IOException { int chararr_count=0; in.readFully(bytearr, 0, utflen); + int ascii = JLA.countPositives(bytearr, 0, utflen); + if (ascii == utflen) { + String str; + if (trusted) { + str = JLA.newStringNoRepl(bytearr, StandardCharsets.ISO_8859_1); + } else { + str = new String(bytearr, 0, utflen, StandardCharsets.ISO_8859_1); + } + return str; + } + if (trusted && in instanceof DataInputStream dis) { + dis.bytearr = bytearr; + trusted = false; + } - while (count < utflen) { - c = (int) bytearr[count] & 0xff; - if (c > 127) break; - count++; - chararr[chararr_count++]=(char)c; + char[] chararr; + if (in instanceof DataInputStream dis) { + if (dis.chararr.length < (utflen << 1)) { + dis.chararr = new char[utflen << 1]; + } + chararr = dis.chararr; + } else { + chararr = new char[utflen]; + } + + if (ascii != 0) { + JLA.inflateBytesToChars(bytearr, 0, chararr, 0, ascii); + count += ascii; + chararr_count += ascii; } while (count < utflen) { 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 5f4e5b72a1919..16f513801a249 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -615,36 +615,77 @@ default CodeBuilder loadConstant(ConstantDesc value) { if (value == null || value == ConstantDescs.NULL) return aconst_null(); if (value instanceof Number) { - if (value instanceof Integer iVal) - return switch (iVal) { - case -1 -> iconst_m1(); - case 0 -> iconst_0(); - case 1 -> iconst_1(); - case 2 -> iconst_2(); - case 3 -> iconst_3(); - case 4 -> iconst_4(); - case 5 -> iconst_5(); - default -> (iVal >= Byte.MIN_VALUE && iVal <= Byte.MAX_VALUE) ? bipush(iVal) - : (iVal >= Short.MIN_VALUE && iVal <= Short.MAX_VALUE) ? sipush(iVal) - : ldc(constantPool().intEntry(iVal)); - }; - if (value instanceof Long lVal) - return lVal == 0L ? lconst_0() - : lVal == 1L ? lconst_1() - : ldc(constantPool().longEntry(lVal)); - if (value instanceof Float fVal) - return Float.floatToRawIntBits(fVal) == 0 ? fconst_0() - : fVal == 1.0f ? fconst_1() - : fVal == 2.0f ? fconst_2() - : ldc(constantPool().floatEntry(fVal)); - if (value instanceof Double dVal) - return Double.doubleToRawLongBits(dVal) == 0L ? dconst_0() - : dVal == 1.0d ? dconst_1() - : ldc(constantPool().doubleEntry(dVal)); + if (value instanceof Integer) return loadConstant((int) value); + if (value instanceof Long ) return loadConstant((long) value); + if (value instanceof Float ) return loadConstant((float) value); + if (value instanceof Double ) return loadConstant((double) value); } return ldc(value); } + + /** + * Generate an instruction pushing a constant int value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Integer.valueOf(value))}. + * @param value the int value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(int value) { + return switch (value) { + case -1 -> iconst_m1(); + case 0 -> iconst_0(); + case 1 -> iconst_1(); + case 2 -> iconst_2(); + case 3 -> iconst_3(); + case 4 -> iconst_4(); + case 5 -> iconst_5(); + default -> (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE ) ? bipush(value) + : (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) ? sipush(value) + : ldc(constantPool().intEntry(value)); + }; + } + + /** + * Generate an instruction pushing a constant long value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Long.valueOf(value))}. + * @param value the long value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(long value) { + return value == 0l ? lconst_0() + : value == 1l ? lconst_1() + : ldc(constantPool().longEntry(value)); + } + + /** + * Generate an instruction pushing a constant float value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Float.valueOf(value))}. + * @param value the float value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(float value) { + return Float.floatToRawIntBits(value) == 0 ? fconst_0() + : value == 1.0f ? fconst_1() + : value == 2.0f ? fconst_2() + : ldc(constantPool().floatEntry(value)); + } + + /** + * Generate an instruction pushing a constant double value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Double.valueOf(value))}. + * @param value the double value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(double value) { + return Double.doubleToRawLongBits(value) == 0l ? dconst_0() + : value == 1.0d ? dconst_1() + : ldc(constantPool().doubleEntry(value)); + } + /** * Generate a do nothing instruction * @return this builder diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 6031b55a107b2..4a905a3030b9a 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -1645,7 +1645,7 @@ private void bogusMethod(ClassBuilder clb, Object os) { clb.withMethodBody("dummy", MTD_void, ACC_STATIC, new Consumer<>() { @Override public void accept(CodeBuilder cob) { - cob.loadConstant(os.toString()); + cob.ldc(os.toString()); cob.pop(); cob.return_(); } diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index 77dfed3b84f2e..3dc3a49dc778e 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -90,7 +90,7 @@ *

If the {@code verify} flag is on when opening a signed jar file, the content * of the jar entry is verified against the signature embedded inside the manifest * that is associated with its {@link JarEntry#getRealName() path name}. For a - * multi-release jar file, the content of a versioned entry is verfieid against + * multi-release jar file, the content of a versioned entry is verified against * its own signature and {@link JarEntry#getCodeSigners()} returns its own signers. * * Please note that the verification process does not include validating the 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 7ef005eaf6a98..5cc08d06ec3ee 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 @@ -57,6 +57,8 @@ import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.Stable; +import static java.lang.classfile.ClassFile.*; + public abstract sealed class AbstractPoolEntry { /* Invariant: a {CP,BSM} entry for pool P refer only to {CP,BSM} entries @@ -96,12 +98,10 @@ public static T maybeClone(ConstantPoolBuilder cp, T entry } final ConstantPool constantPool; - public final byte tag; private final int index; private final int hash; - private AbstractPoolEntry(ConstantPool constantPool, int tag, int index, int hash) { - this.tag = (byte) tag; + private AbstractPoolEntry(ConstantPool constantPool, int index, int hash) { this.index = index; this.hash = hash; this.constantPool = constantPool; @@ -116,12 +116,10 @@ public int hashCode() { return hash; } - public byte tag() { - return tag; - } + public abstract byte tag(); public int width() { - return (tag == ClassFile.TAG_LONG || tag == ClassFile.TAG_DOUBLE) ? 2 : 1; + return 1; } abstract void writeTo(BufWriterImpl buf); @@ -159,7 +157,7 @@ enum State { RAW, BYTE, CHAR, STRING } Utf8EntryImpl(ConstantPool cpm, int index, byte[] rawBytes, int offset, int rawLen) { - super(cpm, ClassFile.TAG_UTF8, index, 0); + super(cpm, index, 0); this.rawBytes = rawBytes; this.offset = offset; this.rawLen = rawLen; @@ -171,7 +169,7 @@ enum State { RAW, BYTE, CHAR, STRING } } Utf8EntryImpl(ConstantPool cpm, int index, String s, int hash) { - super(cpm, ClassFile.TAG_UTF8, index, 0); + super(cpm, index, 0); this.rawBytes = null; this.offset = 0; this.rawLen = 0; @@ -182,7 +180,7 @@ enum State { RAW, BYTE, CHAR, STRING } } Utf8EntryImpl(ConstantPool cpm, int index, Utf8EntryImpl u) { - super(cpm, ClassFile.TAG_UTF8, index, 0); + super(cpm, index, 0); this.rawBytes = u.rawBytes; this.offset = u.offset; this.rawLen = u.rawLen; @@ -194,6 +192,11 @@ enum State { RAW, BYTE, CHAR, STRING } this.typeSym = u.typeSym; } + @Override + public byte tag() { + return TAG_UTF8; + } + /** * {@jvms 4.4.7} String content is encoded in modified UTF-8. * @@ -417,7 +420,7 @@ public boolean equalsString(String s) { @Override void writeTo(BufWriterImpl pool) { - pool.writeU1(tag); + pool.writeU1(TAG_UTF8); if (rawBytes != null) { pool.writeU2(rawLen); pool.writeBytes(rawBytes, offset, rawLen); @@ -449,7 +452,7 @@ abstract static sealed class AbstractRefEntry extends Abstr protected final T ref1; public AbstractRefEntry(ConstantPool constantPool, int tag, int index, T ref1) { - super(constantPool, tag, index, hash1(tag, ref1.index())); + super(constantPool, index, hash1(tag, ref1.index())); this.ref1 = ref1; } @@ -458,7 +461,7 @@ public T ref1() { } void writeTo(BufWriterImpl pool) { - pool.writeU1(tag); + pool.writeU1(tag()); pool.writeU2(ref1.index()); } @@ -474,7 +477,7 @@ abstract static sealed class AbstractRefsEntryAnnotation processing happens in a sequence of {@linkplain - * javax.annotation.processing.RoundEnvironment rounds}. On each - * round, a processor may be asked to {@linkplain #process process} a - * subset of the annotations found on the source and class files - * produced by a prior round. The inputs to the first round of - * processing are the initial inputs to a run of the tool; these + * The interface for an {@index "annotation processor"}. + * + *

Annotation processing happens in a sequence of rounds. + * On each + * {@linkplain RoundEnvironment round}, a processor may be asked to {@linkplain #process process} a + * subset of the annotations found on the + * {@linkplain RoundEnvironment#getRootElements() source and class files + * produced by a prior round}. The inputs to the first round of + * processing are the {@index "initial inputs"} to a run of the tool; these * initial inputs can be regarded as the output of a virtual zeroth * round of processing. If a processor was asked to process on a * given round, it will be asked to process on subsequent rounds, @@ -77,7 +78,7 @@ * protocol being followed, then the processor's behavior is not * defined by this interface specification. * - *

The tool uses a discovery process to find annotation + *

The tool uses a {@index "discovery process"} to find annotation * processors and decide whether or not they should be run. By * configuring the tool, the set of potential processors can be * controlled. For example, for a {@link javax.tools.JavaCompiler diff --git a/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java b/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java index 10363b5a618d1..6dc1b1ccab129 100644 --- a/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java +++ b/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,8 +41,8 @@ * * As defined by The Java Language Specification * section {@jls 9.7.4}, an annotation on an element is a - * declaration annotation and an annotation on a type is a - * type annotation. + * {@index "declaration annotation"} and an annotation on a type is a + * {@index "type annotation"}. * * The terms directly present, present, * indirectly present, and associated are used @@ -54,7 +54,7 @@ * annotation interface AI. If AI is a repeatable annotation * interface, the type of the containing annotation is AIC. * - *

Annotation A is directly present on a construct + *

Annotation A is {@index "directly present"} on a construct * C if either: * *

    @@ -87,7 +87,7 @@ * *
* - *

An annotation A is present on a + *

An annotation A is {@index "present"} on a * construct C if either: *

    * @@ -99,7 +99,7 @@ * *
* - * An annotation A is indirectly present on a construct + * An annotation A is {@index "indirectly present"} on a construct * C if both: * *
    @@ -114,7 +114,7 @@ * *
* - * An annotation A is associated with a construct + * An annotation A is {@index "associated"} with a construct * C if either: * *
    diff --git a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java index 138f093be2f57..1faae30df5723 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java @@ -26,7 +26,7 @@ package javax.lang.model.element; /** - * The nesting kind of a type element. + * The nesting kind of a type element. * Type elements come in four varieties: * top-level, member, local, and anonymous. * Nesting kind is a non-standard term used here to denote this @@ -107,7 +107,7 @@ public enum NestingKind { /** * Does this constant correspond to a nested type element? - * A nested type element is any that is not top-level. + * A nested type element is any that is not top-level. * More specifically, an inner type element is any nested type element that * is not {@linkplain Modifier#STATIC static}. * @return whether or not the constant is nested diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index 0cea2734e213c..bbbf4e3d95e6a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -185,7 +185,7 @@ public interface Types { /** * {@return the class of a boxed value of the primitive type argument} - * That is, boxing conversion is applied. + * That is, boxing conversion is applied. * * @param p the primitive type to be converted * @jls 5.1.7 Boxing Conversion diff --git a/test/hotspot/jtreg/containers/systemd/TEST.properties b/test/hotspot/jtreg/containers/systemd/TEST.properties new file mode 100644 index 0000000000000..d563e5f166403 --- /dev/null +++ b/test/hotspot/jtreg/containers/systemd/TEST.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +exclusiveAccess.dirs=. diff --git a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java index 341b24c3e051a..9acff93aaca23 100644 --- a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java +++ b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java @@ -28,6 +28,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -92,19 +93,23 @@ public static OutputAnalyzer buildAndRunSystemdJava(SystemdRunOptions opts) thro try { return SystemdTestUtils.systemdRunJava(opts); } finally { - try { - if (files.memory() != null) { - Files.delete(files.memory()); - } - if (files.cpu() != null) { - Files.delete(files.cpu()); - } - if (files.sliceDotDDir() != null) { - FileUtils.deleteFileTreeUnchecked(files.sliceDotDDir()); - } - } catch (NoSuchFileException e) { - // ignore + cleanupFiles(files); + } + } + + private static void cleanupFiles(ResultFiles files) throws IOException { + try { + if (files.memory() != null) { + Files.delete(files.memory()); } + if (files.cpu() != null) { + Files.delete(files.cpu()); + } + if (files.sliceDotDDir() != null) { + FileUtils.deleteFileTreeUnchecked(files.sliceDotDDir()); + } + } catch (NoSuchFileException e) { + // ignore } } @@ -135,15 +140,23 @@ private static ResultFiles buildSystemdSlices(SystemdRunOptions runOpts) throws if (runOpts.hasSliceDLimit()) { String dirName = String.format("%s.slice.d", SLICE_NAMESPACE_PREFIX); sliceDotDDir = SYSTEMD_CONFIG_HOME.resolve(Path.of(dirName)); - Files.createDirectory(sliceDotDDir); + // Using createDirectories since we only need to ensure the directory + // exists. Ignore it if already existent. + Files.createDirectories(sliceDotDDir); if (runOpts.sliceDMemoryLimit != null) { Path memoryConfig = sliceDotDDir.resolve(Path.of(SLICE_D_MEM_CONFIG_FILE)); - Files.writeString(memoryConfig, getMemoryDSliceContent(runOpts)); + Files.writeString(memoryConfig, + getMemoryDSliceContent(runOpts), + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); } if (runOpts.sliceDCpuLimit != null) { Path cpuConfig = sliceDotDDir.resolve(Path.of(SLICE_D_CPU_CONFIG_FILE)); - Files.writeString(cpuConfig, getCPUDSliceContent(runOpts)); + Files.writeString(cpuConfig, + getCPUDSliceContent(runOpts), + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); } } @@ -159,7 +172,7 @@ private static ResultFiles buildSystemdSlices(SystemdRunOptions runOpts) throws throw new AssertionError("Failed to write systemd slice files"); } - systemdDaemonReload(cpu); + systemdDaemonReload(cpu, memory, sliceDotDDir); return new ResultFiles(memory, cpu, sliceDotDDir); } @@ -175,12 +188,25 @@ private static String sliceNameCpu(SystemdRunOptions runOpts) { return String.format("%s-cpu", slice); } - private static void systemdDaemonReload(Path cpu) throws Exception { + private static void systemdDaemonReload(Path cpu, Path memory, Path sliceDdir) throws Exception { List daemonReload = systemCtl(); daemonReload.add("daemon-reload"); if (execute(daemonReload).getExitValue() != 0) { - throw new AssertionError("Failed to reload systemd daemon"); + if (RUN_AS_USER) { + cleanupFiles(new ResultFiles(cpu, memory, sliceDdir)); + // When run as user the systemd user manager needs to be + // accessible and working. This is usually the case when + // connected via SSH or user login, but may not work for + // sessions set up via 'su ' or similar. + // In that case, 'systemctl --user status' usually doesn't + // work. There is no other option than skip the test. + String msg = "Service user@.service not properly configured. " + + "Skipping the test!"; + throw new SkippedException(msg); + } else { + throw new AssertionError("Failed to reload systemd daemon"); + } } }