diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index aee4a30b6499e..0e30575ecd011 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -4286,6 +4286,7 @@ template #undef INSN Assembler(CodeBuffer* code) : AbstractAssembler(code) { + MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); } // Stack overflow checking diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index f14dda0f81295..7e280d26805d2 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -271,7 +271,9 @@ class Patcher : public RelocActions { virtual reloc_insn adrpMovk() { return &Patcher::adrpMovk_impl; } public: - Patcher(address insn_addr) : RelocActions(insn_addr) {} + Patcher(address insn_addr) : RelocActions(insn_addr) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); + } virtual int unconditionalBranch(address insn_addr, address &target) { intptr_t offset = (target - insn_addr) >> 2; diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 33158d6b97a91..6f08d5add2578 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -77,6 +77,7 @@ address NativeCall::destination() const { // // Used in the runtime linkage of calls; see class CompiledIC. void NativeCall::set_destination_mt_safe(address dest) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); assert((CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); @@ -143,6 +144,7 @@ intptr_t NativeMovConstReg::data() const { } void NativeMovConstReg::set_data(intptr_t x) { + ////MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); if (maybe_cpool_ref(instruction_address())) { address addr = MacroAssembler::target_addr_for_insn(instruction_address()); *(intptr_t*)addr = x; @@ -239,6 +241,7 @@ void NativeJump::set_jump_destination(address dest) { if (dest == (address) -1) dest = instruction_address(); + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); MacroAssembler::pd_patch_instruction(instruction_address(), dest); ICache::invalidate_range(instruction_address(), instruction_size); }; @@ -262,6 +265,7 @@ address NativeGeneralJump::jump_destination() const { } void NativeGeneralJump::set_jump_destination(address dest) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); NativeMovConstReg* move = nativeMovConstReg_at(instruction_address()); // We use jump to self as the unresolved address which the inline @@ -369,6 +373,7 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add || nativeInstruction_at(verified_entry)->is_sigill_not_entrant(), "Aarch64 cannot replace non-jump with jump"); + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); // Patch this nmethod atomically. if (Assembler::reachable_from_branch_at(verified_entry, dest)) { ptrdiff_t disp = dest - verified_entry; @@ -418,6 +423,7 @@ void NativeCallTrampolineStub::set_destination(address new_destination) { void NativeCall::trampoline_jump(CodeBuffer &cbuf, address dest, JVMCI_TRAPS) { MacroAssembler a(&cbuf); + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); if (!a.far_branches()) { // If not using far branches, patch this call directly to dest. set_destination(dest); diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 0eb5ff815be1d..d124231e9825a 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -91,16 +91,18 @@ class NativeInstruction { s_char sbyte_at(int offset) const { return *(s_char*)addr_at(offset); } u_char ubyte_at(int offset) const { return *(u_char*)addr_at(offset); } - jint int_at(int offset) const { return *(jint*)addr_at(offset); } - juint uint_at(int offset) const { return *(juint*)addr_at(offset); } - address ptr_at(int offset) const { return *(address*)addr_at(offset); } - oop oop_at(int offset) const { return *(oop*)addr_at(offset); } - - void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; } - void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; } - void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; } - void set_ptr_at(int offset, address ptr) { *(address*)addr_at(offset) = ptr; } - void set_oop_at(int offset, oop o) { *(oop*)addr_at(offset) = o; } + jint int_at(int offset) const { return *(jint*)addr_at(offset); } + juint uint_at(int offset) const { return *(juint*)addr_at(offset); } + address ptr_at(int offset) const { return *(address*)addr_at(offset); } + oop oop_at(int offset) const { return *(oop*)addr_at(offset); } + +#define APPLE_WX_WRITE MACOS_AARCH64_ONLY(os::thread_wx_enable_write()) + void set_char_at(int offset, char c) { APPLE_WX_WRITE; *addr_at(offset) = (u_char)c; } + void set_int_at(int offset, jint i) { APPLE_WX_WRITE; *(jint*)addr_at(offset) = i; } + void set_uint_at(int offset, jint i) { APPLE_WX_WRITE; *(juint*)addr_at(offset) = i; } + void set_ptr_at(int offset, address ptr) { APPLE_WX_WRITE; *(address*)addr_at(offset) = ptr; } + void set_oop_at(int offset, oop o) { APPLE_WX_WRITE; *(oop*)addr_at(offset) = o; } +#undef APPLE_WX_WRITE void wrote(int offset); diff --git a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp index 11ea02621d765..a201f473bdfb3 100644 --- a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp @@ -47,6 +47,8 @@ extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int #endif VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); + // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing. const int stub_code_length = code_size_limit(true); VtableStub* s = new(stub_code_length) VtableStub(true, vtable_index); @@ -137,6 +139,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { VtableStub* VtableStubs::create_itable_stub(int itable_index) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing. const int stub_code_length = code_size_limit(false); VtableStub* s = new(stub_code_length) VtableStub(false, itable_index); diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 5ba40651875c5..2369a849b5037 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2214,7 +2214,7 @@ uint os::processor_id() { } void os::set_native_thread_name(const char *name) { -#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 +#if true || defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 // This is only supported in Snow Leopard and beyond if (name != nullptr) { // Add a "Java: " prefix to the name diff --git a/src/hotspot/os_cpu/bsd_aarch64/globals_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/globals_bsd_aarch64.hpp index 4a10e7af091ba..9646e6e8360bb 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/globals_bsd_aarch64.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/globals_bsd_aarch64.hpp @@ -41,4 +41,6 @@ define_pd_global(uintx,JVMInvokeMethodSlack, 8192); // Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx,HeapBaseMinAddress, 2*G); +define_pd_global(bool, TraceWXHealing, false); + #endif // OS_CPU_BSD_AARCH64_GLOBALS_BSD_AARCH64_HPP diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp index aeba308d3a2e2..35c78cddc7125 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -199,19 +199,33 @@ NOINLINE frame os::current_frame() { bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ucontext_t* uc, JavaThread* thread) { - // Enable WXWrite: this function is called by the signal handler at arbitrary - // point of execution. - ThreadWXEnable wx(WXWrite, thread); - // decide if this trap can be handled by a stub address stub = nullptr; - - address pc = nullptr; + address pc = nullptr; //%note os_trap_1 if (info != nullptr && uc != nullptr && thread != nullptr) { pc = (address) os::Posix::ucontext_get_pc(uc); +#ifdef __APPLE__ + // If we got a SIGBUS because we tried to write into the code + // cache, try enabling WXWrite mode. + if (sig == SIGBUS && pc != info->si_addr && CodeCache::contains(info->si_addr)) { + if (thread->_cur_wx_mode) { + if (TraceWXHealing) { + fprintf(stderr, "Healing pointer at %p to WXWrite\n", thread->_cur_wx_mode); + } + *(thread->_cur_wx_mode) = WXWrite; + } + return thread->wx_enable_write(); + } +#endif + + // Enable WXWrite for the duration of this handler: this function + // is called by the signal handler at arbitrary point of + // execution. + ThreadWXEnable wx(WXWrite, thread); + // Handle ALL stack overflow variations here if (sig == SIGSEGV || sig == SIGBUS) { address addr = (address) info->si_addr; @@ -488,10 +502,74 @@ int os::extra_bang_size_in_bytes() { return 0; } +// DEBUG CODE: REMOVE BEFORE SHIPPING +#if defined(__APPLE__) && defined(AARCH64) + +#ifndef PRODUCT + +long pthread_jit_write_protect_np_counter; +long pthread_jit_write_protect_not_counter; + +bool aph_do_trace; +FILE *aph_do_trace_file; + +void poo() __attribute__((constructor)); +void poo() { + atexit([]() { + fclose(aph_do_trace_file); + if (getenv("JDK_PRINT_WX_COUNTER")) { + printf("pthread_jit_write_protect_np_counter == %ld\n", pthread_jit_write_protect_np_counter); + printf("pthread_jit_write_protect_not_counter == %ld\n", pthread_jit_write_protect_not_counter); + } + }); + aph_do_trace = getenv("APH_DO_TRACE"); + if (aph_do_trace) { + errno = 0; + aph_do_trace_file = fopen("/Users/aph/aph_trace", "w+"); + if (errno) { + perror("fopen failed\n"); + } + } +} + +#endif // ! PRODUCT + +static THREAD_LOCAL bool os_bsd_jit_exec_enabled; +// This is a wrapper around the standard library function +// pthread_jit_write_protect_np(3). We keep track of the state of +// per-thread write protection on the MAP_JIT region in the +// thread-local variable os_bsd_jit_exec_enabled. void os::current_thread_enable_wx(WXMode mode) { - pthread_jit_write_protect_np(mode == WXExec); + bool exec_enabled = mode != WXWrite; + if (exec_enabled != os_bsd_jit_exec_enabled) { + permit_forbidden_function::pthread_jit_write_protect_np(exec_enabled); + os_bsd_jit_exec_enabled = exec_enabled; + NOT_PRODUCT(pthread_jit_write_protect_np_counter++); + } else { + NOT_PRODUCT(pthread_jit_write_protect_not_counter++); + } } +// If the current thread is in the WX state WXArmedForWrite, change +// the state to WXWrite. +bool Thread::wx_enable_write() { + if (_wx_state == WXArmedForWrite) { + _wx_state = WXWrite; + os::current_thread_enable_wx(WXWrite); + return true; + } else { + return false; + } +} + +// A wrapper around wx_enable_write() for when the current thread is +// not known. +void os::thread_wx_enable_write() { + Thread::current()->wx_enable_write(); +} + +#endif // defined(__APPLE__) && defined(AARCH64) + static inline void atomic_copy64(const volatile void *src, volatile void *dst) { *(jlong *) dst = *(const jlong *) src; } diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index ca25cf56be085..69c7575685fe1 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -97,6 +97,8 @@ CodeBuffer::CodeBuffer(CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this) } void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); + // Always allow for empty slop around each section. int slop = (int) CodeSection::end_slop(); diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 4bf056fe312ca..ee754e65f7018 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -544,6 +544,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c // Reset method handle flag. current->set_is_method_handle_return(false); +MACOS_AARCH64_ONLY(current->wx_enable_write()); Handle exception(current, ex); // This function is called when we are about to throw an exception. Therefore, diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index da0408d1270c7..9a7ea99bdd582 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -398,6 +398,7 @@ BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, int size) {} BufferBlob* BufferBlob::create(const char* name, uint buffer_size) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock BufferBlob* blob = nullptr; diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index ed6167dac225b..550598f634e63 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1931,6 +1931,7 @@ void nmethod::verify_clean_inline_caches() { } void nmethod::mark_as_maybe_on_stack() { + MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); Atomic::store(&_gc_epoch, CodeCache::gc_epoch()); } @@ -2397,6 +2398,8 @@ class IsUnloadingState: public AllStatic { }; bool nmethod::is_unloading() { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); + uint8_t state = Atomic::load(&_is_unloading_state); bool state_is_unloading = IsUnloadingState::is_unloading(state); if (state_is_unloading) { diff --git a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp index 41eb0a24b625a..f48251b9ff05e 100644 --- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp @@ -167,7 +167,7 @@ void BarrierSetNMethod::arm_all_nmethods() { int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) { // Enable WXWrite: the function is called directly from nmethod_entry_barrier // stub. - MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current())); + MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXArmedForWrite, Thread::current())); address return_address = *return_address_ptr; AARCH64_PORT_ONLY(return_address = pauth_strip_pointer(return_address)); diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 195bf57e055fa..20cd4cfd447f9 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -386,6 +386,7 @@ JRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* current, char* JRT_END + JRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* current, char* name, oopDesc* obj)) // Produce the error message first because note_trap can safepoint ResourceMark rm(current); diff --git a/src/hotspot/share/memory/heap.cpp b/src/hotspot/share/memory/heap.cpp index bcb9d2e6114b9..e5615279eca42 100644 --- a/src/hotspot/share/memory/heap.cpp +++ b/src/hotspot/share/memory/heap.cpp @@ -163,6 +163,7 @@ void CodeHeap::mark_segmap_as_used(size_t beg, size_t end, bool is_FreeBlock_joi void CodeHeap::invalidate(size_t beg, size_t end, size_t hdr_size) { #ifndef PRODUCT + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); // Fill the given range with some bad value. // length is expected to be in segment_size units. // This prevents inadvertent execution of code leftover from previous use. @@ -172,11 +173,13 @@ void CodeHeap::invalidate(size_t beg, size_t end, size_t hdr_size) { } void CodeHeap::clear(size_t beg, size_t end) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); mark_segmap_as_free(beg, end); invalidate(beg, end, 0); } void CodeHeap::clear() { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); _next_segment = 0; clear(_next_segment, _number_of_committed_segments); } @@ -198,6 +201,7 @@ void CodeHeap::on_code_mapping(char* base, size_t size) { bool CodeHeap::reserve(ReservedSpace rs, size_t committed_size, size_t segment_size) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); assert(rs.size() >= committed_size, "reserved < committed"); assert(is_aligned(committed_size, rs.page_size()), "must be page aligned"); assert(segment_size >= sizeof(FreeBlock), "segment size is too small"); @@ -239,6 +243,7 @@ bool CodeHeap::reserve(ReservedSpace rs, size_t committed_size, size_t segment_s bool CodeHeap::expand_by(size_t size) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); assert_locked_or_safepoint(CodeCache_lock); // expand _memory space @@ -269,6 +274,7 @@ bool CodeHeap::expand_by(size_t size) { void* CodeHeap::allocate(size_t instance_size) { + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); size_t number_of_segments = size_to_segments(instance_size + header_size()); assert(segments_to_size(number_of_segments) >= sizeof(FreeBlock), "not enough room for FreeList"); assert_locked_or_safepoint(CodeCache_lock); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index c5e15b5f3a648..9c41b34cfa771 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1818,6 +1818,8 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* c // has updated oops. StackWatermarkSet::after_unwind(current); + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); + // Do not confuse exception_oop with pending_exception. The exception_oop // is only used to pass arguments into the method. Not for general // exception handling. DO NOT CHANGE IT to use pending_exception, since diff --git a/src/hotspot/share/prims/upcallStubs.cpp b/src/hotspot/share/prims/upcallStubs.cpp index 5215e6d1735f0..01c91a534a2fb 100644 --- a/src/hotspot/share/prims/upcallStubs.cpp +++ b/src/hotspot/share/prims/upcallStubs.cpp @@ -26,6 +26,7 @@ #include "runtime/interfaceSupport.inline.hpp" JVM_ENTRY(static jboolean, UH_FreeUpcallStub0(JNIEnv *env, jobject _unused, jlong addr)) + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); // safe to call 'find_blob' without code cache lock, because stub is always alive CodeBlob* cb = CodeCache::find_blob((char*)addr); if (cb == nullptr) { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 8478cad4df5af..d267e40cfc6f5 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -134,6 +134,7 @@ void DeoptimizationScope::mark(nmethod* nm, bool inc_recompile_counts) { return; } + //MACOS_AARCH64_ONLY(os::thread_wx_enable_write()); nmethod::DeoptimizationStatus status = inc_recompile_counts ? nmethod::deoptimize : nmethod::deoptimize_noupdate; Atomic::store(&nm->_deoptimization_status, status); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 3f4dfa1007060..b76059127fbbb 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -2009,6 +2009,10 @@ const int ObjectAlignmentInBytes = 8; product(bool, UseThreadsLockThrottleLock, true, DIAGNOSTIC, \ "Use an extra lock during Thread start and exit to alleviate" \ "contention on Threads_lock.") \ + \ + develop_pd(bool, TraceWXHealing, \ + "track occurrences of W^X mode healing") \ + // end of RUNTIME_FLAGS diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index c52c2664faa51..97771ef3fe55d 100644 --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp @@ -279,13 +279,13 @@ class VMNativeEntryWrapper { os::verify_stack_alignment(); \ /* begin of body */ - -#define JRT_ENTRY(result_type, header) \ - result_type header { \ - assert(current == JavaThread::current(), "Must be"); \ - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ - ThreadInVMfromJava __tiv(current); \ - VM_ENTRY_BASE(result_type, header, current) \ +#define JRT_ENTRY(result_type, header) \ + result_type header { \ + assert(current == JavaThread::current(), "Must be"); \ + static WXMode wx_mode = WXArmedForWrite; \ + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(&wx_mode, current)); \ + ThreadInVMfromJava __tiv(current); \ + VM_ENTRY_BASE(result_type, header, current) \ DEBUG_ONLY(VMEntryWrapper __vew;) // JRT_LEAF currently can be called from either _thread_in_Java or @@ -311,7 +311,8 @@ class VMNativeEntryWrapper { #define JRT_ENTRY_NO_ASYNC(result_type, header) \ result_type header { \ assert(current == JavaThread::current(), "Must be"); \ - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ + static WXMode wx_mode = WXArmedForWrite; \ + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(&wx_mode, current)); \ ThreadInVMfromJava __tiv(current, false /* check asyncs */); \ VM_ENTRY_BASE(result_type, header, current) \ DEBUG_ONLY(VMEntryWrapper __vew;) @@ -321,7 +322,8 @@ class VMNativeEntryWrapper { #define JRT_BLOCK_ENTRY(result_type, header) \ result_type header { \ assert(current == JavaThread::current(), "Must be"); \ - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ + static WXMode wx_mode = WXArmedForWrite; \ + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(&wx_mode, current)); \ HandleMarkCleaner __hm(current); #define JRT_BLOCK \ @@ -340,7 +342,8 @@ class VMNativeEntryWrapper { #define JRT_BLOCK_END } -#define JRT_END } +#define JRT_END \ +} // Definitions for JNI // @@ -358,7 +361,8 @@ extern "C" { \ result_type JNICALL header { \ JavaThread* thread=JavaThread::thread_from_jni_environment(env); \ assert(thread == Thread::current(), "JNIEnv is only valid in same thread"); \ - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); \ + static WXMode wx_mode = WXArmedForWrite; \ + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(&wx_mode, thread)); \ ThreadInVMfromNative __tiv(thread); \ DEBUG_ONLY(VMNativeEntryWrapper __vew;) \ VM_ENTRY_BASE(result_type, header, thread) @@ -383,7 +387,8 @@ extern "C" { \ extern "C" { \ result_type JNICALL header { \ JavaThread* thread=JavaThread::thread_from_jni_environment(env); \ - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); \ + static WXMode wx_mode = WXArmedForWrite; \ + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(&wx_mode, thread)); \ ThreadInVMfromNative __tiv(thread); \ DEBUG_ONLY(VMNativeEntryWrapper __vew;) \ VM_ENTRY_BASE(result_type, header, thread) @@ -393,7 +398,8 @@ extern "C" { \ extern "C" { \ result_type JNICALL header { \ JavaThread* thread = JavaThread::current(); \ - MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); \ + static WXMode wx_mode = WXArmedForWrite; \ + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(&wx_mode, thread)); \ ThreadInVMfromNative __tiv(thread); \ DEBUG_ONLY(VMNativeEntryWrapper __vew;) \ VM_ENTRY_BASE(result_type, header, thread) diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index 04bd08710739d..3b1075f44fcd3 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -316,6 +316,7 @@ Handle JavaCalls::construct_new_instance(InstanceKlass* klass, Symbol* construct void JavaCalls::call(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) { + MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXExec, THREAD)); // Check if we need to wrap a potential OS exception handler around thread. // This is used for e.g. Win32 structured exception handlers. // Need to wrap each and every time, since there might be native code down the @@ -326,6 +327,7 @@ void JavaCalls::call(JavaValue* result, const methodHandle& method, JavaCallArgu void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) { JavaThread* thread = THREAD; + MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXExec, THREAD)); assert(method.not_null(), "must have a method to call"); assert(!SafepointSynchronize::is_at_safepoint(), "call to Java code during VM operation"); assert(!thread->handle_area()->no_handle_mark_active(), "cannot call out to Java here"); diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 6f4d418595656..4a9b79bfd251b 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -383,7 +383,7 @@ void JavaThread::check_possible_safepoint() { // happens in practice, making such issues hard to find and reproduce. #if defined(__APPLE__) && defined(AARCH64) if (AssertWXAtThreadSync) { - assert_wx_state(WXWrite); + // assert_wx_state(WXWrite); } #endif } @@ -518,8 +518,11 @@ JavaThread::JavaThread(MemTag mem_tag) : _last_freeze_fail_result(freeze_ok), #endif + _cur_wx_enable(nullptr), + _cur_wx_mode(0), + _lock_stack(this), - _om_cache(this) { + _om_cache(this) { set_jni_functions(jni_functions()); #if INCLUDE_JVMCI diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index ab3b3611f1dab..e6f697db25276 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -80,6 +80,7 @@ class JavaThread; typedef void (*ThreadFunction)(JavaThread*, TRAPS); class EventVirtualThreadPinned; +class ThreadWXEnable; class JavaThread: public Thread { friend class VMStructs; @@ -168,7 +169,7 @@ class JavaThread: public Thread { // attached thread cases where this field can have a temporary value. int64_t _monitor_owner_id; - public: +public: void set_monitor_owner_id(int64_t id) { ThreadIdentifier::verify_id(id); _monitor_owner_id = id; @@ -1264,6 +1265,10 @@ class JavaThread: public Thread { // the Java code in Object::wait which are not present in RawMonitorWait. bool get_and_clear_interrupted(); +public: + ThreadWXEnable* _cur_wx_enable; + WXMode* _cur_wx_mode; + private: LockStack _lock_stack; OMCache _om_cache; diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index dde80806912f5..a679183af32d0 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -141,8 +141,9 @@ enum ThreadPriority { // JLS 20.20.1-3 }; enum WXMode { - WXWrite, - WXExec + WXWrite = 0, + WXExec = 1, + WXArmedForWrite = 2, }; // Executable parameter flag for os::commit_memory() and @@ -1075,6 +1076,8 @@ class os: AllStatic { #if defined(__APPLE__) && defined(AARCH64) // Enables write or execute access to writeable and executable pages. static void current_thread_enable_wx(WXMode mode); + // Macos-AArch64 only. + static void thread_wx_enable_write(); #endif // __APPLE__ && AARCH64 protected: diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 0d245dae857c1..70a7cbc59c028 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -596,3 +596,4 @@ void Thread::SpinRelease(volatile int * adr) { // more than covers this on all platforms. *adr = 0; } + diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 7ab86121b89ac..d512a789b0308 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -613,10 +613,13 @@ class Thread: public ThreadShadow { public: void init_wx(); WXMode enable_wx(WXMode new_state); - + bool wx_enable_write(); void assert_wx_state(WXMode expected) { assert(_wx_state == expected, "wrong state"); } + WXMode get_wx_state() { + return _wx_state; + } #endif // __APPLE__ && AARCH64 private: diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp index 756a4702159d2..247315fc515b0 100644 --- a/src/hotspot/share/runtime/thread.inline.hpp +++ b/src/hotspot/share/runtime/thread.inline.hpp @@ -30,6 +30,7 @@ #include "gc/shared/tlab_globals.hpp" #include "runtime/atomic.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #if defined(__APPLE__) && defined(AARCH64) #include "runtime/os.hpp" @@ -75,6 +76,7 @@ inline void Thread::init_wx() { assert(this == Thread::current(), "should only be called for current thread"); assert(!_wx_init, "second init"); _wx_state = WXWrite; + permit_forbidden_function::pthread_jit_write_protect_np(false); os::current_thread_enable_wx(_wx_state); DEBUG_ONLY(_wx_init = true); } @@ -85,10 +87,19 @@ inline WXMode Thread::enable_wx(WXMode new_state) { WXMode old = _wx_state; if (_wx_state != new_state) { _wx_state = new_state; - os::current_thread_enable_wx(new_state); + switch (new_state) { + case WXWrite: + case WXExec: + os::current_thread_enable_wx(new_state); + break; + case WXArmedForWrite: + break; + default: ShouldNotReachHere(); break; + } } return old; } + #endif // __APPLE__ && AARCH64 #endif // SHARE_RUNTIME_THREAD_INLINE_HPP diff --git a/src/hotspot/share/runtime/threadWXSetters.inline.hpp b/src/hotspot/share/runtime/threadWXSetters.inline.hpp index 121584b81be85..e0c07257f27fa 100644 --- a/src/hotspot/share/runtime/threadWXSetters.inline.hpp +++ b/src/hotspot/share/runtime/threadWXSetters.inline.hpp @@ -33,16 +33,46 @@ #include "runtime/thread.inline.hpp" class ThreadWXEnable { - Thread* _thread; + Thread *_thread; WXMode _old_mode; + WXMode *_this_wx_mode; + ThreadWXEnable *_prev; public: + ThreadWXEnable(WXMode* new_mode, Thread* thread) : + _thread(thread), _this_wx_mode(new_mode) { + JavaThread *javaThread + = _thread && _thread->is_Java_thread() + ? JavaThread::cast(_thread) : nullptr; + _prev = javaThread ? javaThread->_cur_wx_enable: nullptr; + _old_mode = _thread ? _thread->enable_wx(*new_mode) : WXWrite; + if (javaThread) { + javaThread->_cur_wx_enable = this; + javaThread->_cur_wx_mode = new_mode; + } + } ThreadWXEnable(WXMode new_mode, Thread* thread) : - _thread(thread), - _old_mode(_thread ? _thread->enable_wx(new_mode) : WXWrite) - { } + _thread(thread), _this_wx_mode(nullptr) { + JavaThread *javaThread + = _thread && _thread->is_Java_thread() + ? JavaThread::cast(_thread) : nullptr; + _prev = javaThread ? javaThread->_cur_wx_enable: nullptr; + _old_mode = _thread ? _thread->enable_wx(new_mode) : WXWrite; + if (javaThread) { + javaThread->_cur_wx_enable = this; + javaThread->_cur_wx_mode = nullptr; + } + } + ~ThreadWXEnable() { if (_thread) { _thread->enable_wx(_old_mode); + JavaThread *javaThread + = _thread && _thread->is_Java_thread() + ? JavaThread::cast(_thread) : nullptr; + if (javaThread) { + javaThread->_cur_wx_enable = _prev; + javaThread->_cur_wx_mode = _prev ? _prev->_this_wx_mode : nullptr; + } } } }; diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 47c030fdb729e..ba7eac9a00006 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -596,6 +596,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { return status; } + MACOS_AARCH64_ONLY(os::current_thread_enable_wx(WXWrite)); + // Have the WatcherThread read the release file in the background. ReadReleaseFileTask* read_task = new ReadReleaseFileTask(); read_task->enroll(); diff --git a/src/hotspot/share/utilities/forbiddenFunctions.hpp b/src/hotspot/share/utilities/forbiddenFunctions.hpp index 0bc34adf213b3..5e546e4bcf965 100644 --- a/src/hotspot/share/utilities/forbiddenFunctions.hpp +++ b/src/hotspot/share/utilities/forbiddenFunctions.hpp @@ -76,4 +76,8 @@ FORBID_IMPORTED_C_FUNCTION(void* realloc(void *ptr, size_t size), "use os::reall FORBID_IMPORTED_C_FUNCTION(char* strdup(const char *s), "use os::strdup"); FORBID_IMPORTED_C_FUNCTION(wchar_t* wcsdup(const wchar_t *s), "don't use"); +// Disallow non-wrapped raw library function. +MACOS_AARCH64_ONLY(FORBID_C_FUNCTION(void pthread_jit_write_protect_np(int enabled), \ + "use os::current_thread_enable_wx");) + #endif // SHARE_UTILITIES_FORBIDDENFUNCTIONS_HPP diff --git a/src/hotspot/share/utilities/permitForbiddenFunctions.hpp b/src/hotspot/share/utilities/permitForbiddenFunctions.hpp index 1ba42f8e386d8..e68b723b0f543 100644 --- a/src/hotspot/share/utilities/permitForbiddenFunctions.hpp +++ b/src/hotspot/share/utilities/permitForbiddenFunctions.hpp @@ -67,6 +67,10 @@ inline void* realloc(void* ptr, size_t size) { return ::realloc(ptr, size); } inline char* strdup(const char* s) { return ::strdup(s); } +MACOS_AARCH64_ONLY( \ + inline void pthread_jit_write_protect_np(int enabled) { return ::pthread_jit_write_protect_np(enabled); } \ +) + END_ALLOW_FORBIDDEN_FUNCTIONS } // namespace permit_forbidden_function