Skip to content

Commit 77e8469

Browse files
Andrew Haleydean-long
andcommitted
8328306: AArch64: MacOS lazy JIT "write xor execute" switching
Co-authored-by: Dean Long <dlong@openjdk.org> Reviewed-by: dlong, adinn
1 parent d1b226d commit 77e8469

35 files changed

+433
-71
lines changed

src/hotspot/cpu/aarch64/assembler_aarch64.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4329,6 +4329,7 @@ template<typename R, typename... Rx>
43294329
#undef INSN
43304330

43314331
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
4332+
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
43324333
}
43334334

43344335
// Stack overflow checking

src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ void BarrierSetNMethod::set_guard_value(nmethod* nm, int value, int bit_mask) {
209209
bs_asm->increment_patching_epoch();
210210
}
211211

212+
// Enable WXWrite: the function is called directly from nmethod_entry_barrier
213+
// stub.
214+
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current()));
215+
212216
NativeNMethodBarrier barrier(nm);
213217
barrier.set_value(value, bit_mask);
214218
}

src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ address MacroAssembler::target_addr_for_insn(address insn_addr) {
473473
// Patch any kind of instruction; there may be several instructions.
474474
// Return the total length (in bytes) of the instructions.
475475
int MacroAssembler::pd_patch_instruction_size(address insn_addr, address target) {
476+
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
476477
return RelocActions<Patcher>::run(insn_addr, target);
477478
}
478479

@@ -481,6 +482,8 @@ int MacroAssembler::patch_oop(address insn_addr, address o) {
481482
unsigned insn = *(unsigned*)insn_addr;
482483
assert(nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
483484

485+
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
486+
484487
// OOPs are either narrow (32 bits) or wide (48 bits). We encode
485488
// narrow OOPs by setting the upper 16 bits in the first
486489
// instruction.
@@ -510,6 +513,8 @@ int MacroAssembler::patch_narrow_klass(address insn_addr, narrowKlass n) {
510513
assert(Instruction_aarch64::extract(insn->encoding(), 31, 21) == 0b11010010101 &&
511514
nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
512515

516+
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
517+
513518
Instruction_aarch64::patch(insn_addr, 20, 5, n >> 16);
514519
Instruction_aarch64::patch(insn_addr+4, 20, 5, n & 0xffff);
515520
return 2 * NativeInstruction::instruction_size;

src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ void NativeMovConstReg::verify() {
133133

134134

135135
intptr_t NativeMovConstReg::data() const {
136-
// das(uint64_t(instruction_address()),2);
137136
address addr = MacroAssembler::target_addr_for_insn(instruction_address());
138137
if (maybe_cpool_ref(instruction_address())) {
139138
return *(intptr_t*)addr;
@@ -144,6 +143,7 @@ intptr_t NativeMovConstReg::data() const {
144143

145144
void NativeMovConstReg::set_data(intptr_t x) {
146145
if (maybe_cpool_ref(instruction_address())) {
146+
MACOS_AARCH64_ONLY(os::thread_wx_enable_write());
147147
address addr = MacroAssembler::target_addr_for_insn(instruction_address());
148148
*(intptr_t*)addr = x;
149149
} else {
@@ -350,8 +350,6 @@ bool NativeInstruction::is_stop() {
350350

351351
//-------------------------------------------------------------------
352352

353-
void NativeGeneralJump::verify() { }
354-
355353
// MT-safe patching of a long jump instruction.
356354
void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
357355
ShouldNotCallThis();

src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,18 @@ class NativeInstruction {
9090

9191
s_char sbyte_at(int offset) const { return *(s_char*)addr_at(offset); }
9292
u_char ubyte_at(int offset) const { return *(u_char*)addr_at(offset); }
93-
jint int_at(int offset) const { return *(jint*)addr_at(offset); }
94-
juint uint_at(int offset) const { return *(juint*)addr_at(offset); }
95-
address ptr_at(int offset) const { return *(address*)addr_at(offset); }
96-
oop oop_at(int offset) const { return *(oop*)addr_at(offset); }
97-
98-
void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; }
99-
void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; }
100-
void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; }
101-
void set_ptr_at(int offset, address ptr) { *(address*)addr_at(offset) = ptr; }
102-
void set_oop_at(int offset, oop o) { *(oop*)addr_at(offset) = o; }
93+
jint int_at(int offset) const { return *(jint*)addr_at(offset); }
94+
juint uint_at(int offset) const { return *(juint*)addr_at(offset); }
95+
address ptr_at(int offset) const { return *(address*)addr_at(offset); }
96+
oop oop_at(int offset) const { return *(oop*)addr_at(offset); }
97+
98+
#define MACOS_WX_WRITE MACOS_AARCH64_ONLY(os::thread_wx_enable_write())
99+
void set_char_at(int offset, char c) { MACOS_WX_WRITE; *addr_at(offset) = (u_char)c; }
100+
void set_int_at(int offset, jint i) { MACOS_WX_WRITE; *(jint*)addr_at(offset) = i; }
101+
void set_uint_at(int offset, jint i) { MACOS_WX_WRITE; *(juint*)addr_at(offset) = i; }
102+
void set_ptr_at(int offset, address ptr) { MACOS_WX_WRITE; *(address*)addr_at(offset) = ptr; }
103+
void set_oop_at(int offset, oop o) { MACOS_WX_WRITE; *(oop*)addr_at(offset) = o; }
104+
#undef MACOS_WX_WRITE
103105

104106
void wrote(int offset);
105107

@@ -380,7 +382,6 @@ class NativeGeneralJump: public NativeJump {
380382
void set_jump_destination(address dest);
381383

382384
static void replace_mt_safe(address instr_addr, address code_buffer);
383-
static void verify();
384385
};
385386

386387
inline NativeGeneralJump* nativeGeneralJump_at(address address) {

src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11742,7 +11742,9 @@ class StubGenerator: public StubCodeGenerator {
1174211742
}
1174311743
#endif
1174411744

11745-
StubRoutines::_unsafe_setmemory = generate_unsafe_setmemory();
11745+
if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_setMemory)) {
11746+
StubRoutines::_unsafe_setmemory = generate_unsafe_setmemory();
11747+
}
1174611748

1174711749
StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated
1174811750
}

src/hotspot/cpu/aarch64/vm_version_aarch64.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,22 @@ void VM_Version::initialize() {
622622

623623
check_virtualizations();
624624

625+
#ifdef __APPLE__
626+
DefaultWXWriteMode = UseOldWX ? WXWrite : WXArmedForWrite;
627+
628+
if (TraceWXHealing) {
629+
if (pthread_jit_write_protect_supported_np()) {
630+
tty->print_cr("### TraceWXHealing is in use");
631+
if (StressWXHealing) {
632+
tty->print_cr("### StressWXHealing is in use");
633+
}
634+
} else {
635+
tty->print_cr("WX Healing is not in use because MAP_JIT write protection "
636+
"does not work on this system.");
637+
}
638+
}
639+
#endif
640+
625641
// Sync SVE related CPU features with flags
626642
if (UseSVE < 2) {
627643
clear_feature(CPU_SVE2);

src/hotspot/os/bsd/globals_bsd.hpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,29 @@
2828
//
2929
// Declare Bsd specific flags. They are not available on other platforms.
3030
//
31+
#ifdef AARCH64
3132
#define RUNTIME_OS_FLAGS(develop, \
3233
develop_pd, \
3334
product, \
3435
product_pd, \
3536
range, \
3637
constraint) \
3738
\
38-
AARCH64_ONLY(develop(bool, AssertWXAtThreadSync, true, \
39-
"Conservatively check W^X thread state at possible safepoint" \
40-
"or handshake"))
39+
develop(bool, TraceWXHealing, false, \
40+
"track occurrences of W^X mode healing") \
41+
develop(bool, UseOldWX, false, \
42+
"Choose old W^X implementation.") \
43+
product(bool, StressWXHealing, false, DIAGNOSTIC, \
44+
"Stress W xor X healing on MacOS")
45+
46+
#else
47+
#define RUNTIME_OS_FLAGS(develop, \
48+
develop_pd, \
49+
product, \
50+
product_pd, \
51+
range, \
52+
constraint)
53+
#endif
4154

4255
// end of RUNTIME_OS_FLAGS
4356

src/hotspot/os/bsd/os_bsd.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ jlong os::javaTimeNanos() {
841841
// We might also condition (c) on the magnitude of the delta between obsv and now.
842842
// Avoiding excessive CAS operations to hot RW locations is critical.
843843
// See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
844+
// https://web.archive.org/web/20131214182431/https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
844845
return (prev == obsv) ? now : obsv;
845846
}
846847

src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,11 @@
5454
#include "signals_posix.hpp"
5555
#include "utilities/align.hpp"
5656
#include "utilities/debug.hpp"
57+
#include "utilities/decoder.hpp"
5758
#include "utilities/events.hpp"
59+
#include "utilities/nativeStackPrinter.hpp"
5860
#include "utilities/vmError.hpp"
61+
#include "compiler/disassembler.hpp"
5962

6063
// put OS-includes here
6164
# include <sys/types.h>
@@ -85,6 +88,8 @@
8588
#define SPELL_REG_SP "sp"
8689

8790
#ifdef __APPLE__
91+
WXMode DefaultWXWriteMode;
92+
8893
// see darwin-xnu/osfmk/mach/arm/_structs.h
8994

9095
// 10.5 UNIX03 member name prefixes
@@ -233,19 +238,56 @@ NOINLINE frame os::current_frame() {
233238

234239
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
235240
ucontext_t* uc, JavaThread* thread) {
236-
// Enable WXWrite: this function is called by the signal handler at arbitrary
237-
// point of execution.
238-
ThreadWXEnable wx(WXWrite, thread);
239-
240241
// decide if this trap can be handled by a stub
241242
address stub = nullptr;
242-
243-
address pc = nullptr;
243+
address pc = nullptr;
244244

245245
//%note os_trap_1
246246
if (info != nullptr && uc != nullptr && thread != nullptr) {
247247
pc = (address) os::Posix::ucontext_get_pc(uc);
248248

249+
#ifdef MACOS_AARCH64
250+
// If we got a SIGBUS because we tried to write into the code
251+
// cache, try enabling WXWrite mode.
252+
if (sig == SIGBUS
253+
&& pc != info->si_addr
254+
&& CodeCache::contains(info->si_addr)
255+
&& os::address_is_in_vm(pc)) {
256+
WXMode *entry_mode = thread->_cur_wx_mode;
257+
if (entry_mode != nullptr && *entry_mode == WXArmedForWrite) {
258+
if (TraceWXHealing) {
259+
static const char *mode_names[3] = {"WXWrite", "WXExec", "WXArmedForWrite"};
260+
tty->print("Healing WXMode %s at %p to WXWrite",
261+
mode_names[*entry_mode], entry_mode);
262+
char name[128];
263+
int offset = 0;
264+
if (os::dll_address_to_function_name(pc, name, sizeof name, &offset)) {
265+
tty->print_cr(" (%s+0x%x)", name, offset);
266+
} else {
267+
tty->cr();
268+
}
269+
if (Verbose) {
270+
char buf[O_BUFLEN];
271+
NativeStackPrinter nsp(thread);
272+
nsp.print_stack(tty, buf, sizeof(buf), pc,
273+
true /* print_source_info */, -1 /* max stack */);
274+
}
275+
}
276+
#ifndef PRODUCT
277+
guarantee(StressWXHealing,
278+
"We should not reach here unless StressWXHealing");
279+
#endif
280+
*(thread->_cur_wx_mode) = WXWrite;
281+
return thread->wx_enable_write();
282+
}
283+
}
284+
285+
// There may be cases where code after this point that we call
286+
// from the signal handler changes WX state, so we protect against
287+
// that by saving and restoring the state.
288+
ThreadWXEnable wx(thread->get_wx_state(), thread);
289+
#endif
290+
249291
// Handle ALL stack overflow variations here
250292
if (sig == SIGSEGV || sig == SIGBUS) {
251293
address addr = (address) info->si_addr;
@@ -515,11 +557,42 @@ int os::extra_bang_size_in_bytes() {
515557
return 0;
516558
}
517559

518-
#ifdef __APPLE__
560+
#ifdef MACOS_AARCH64
561+
THREAD_LOCAL bool os::_jit_exec_enabled;
562+
563+
// This is a wrapper around the standard library function
564+
// pthread_jit_write_protect_np(3). We keep track of the state of
565+
// per-thread write protection on the MAP_JIT region in the
566+
// thread-local variable os::_jit_exec_enabled
519567
void os::current_thread_enable_wx(WXMode mode) {
520-
pthread_jit_write_protect_np(mode == WXExec);
568+
bool exec_enabled = mode != WXWrite;
569+
if (exec_enabled != _jit_exec_enabled NOT_PRODUCT( || DefaultWXWriteMode == WXWrite)) {
570+
permit_forbidden_function::pthread_jit_write_protect_np(exec_enabled);
571+
_jit_exec_enabled = exec_enabled;
572+
}
521573
}
522-
#endif
574+
575+
// If the current thread is in the WX state WXArmedForWrite, change
576+
// the state to WXWrite.
577+
bool Thread::wx_enable_write() {
578+
if (_wx_state == WXArmedForWrite) {
579+
_wx_state = WXWrite;
580+
os::current_thread_enable_wx(WXWrite);
581+
return true;
582+
} else {
583+
return false;
584+
}
585+
}
586+
587+
// A wrapper around wx_enable_write() for when the current thread is
588+
// not known.
589+
void os::thread_wx_enable_write_impl() {
590+
if (!StressWXHealing) {
591+
Thread::current()->wx_enable_write();
592+
}
593+
}
594+
595+
#endif // MACOS_AARCH64
523596

524597
static inline void atomic_copy64(const volatile void *src, volatile void *dst) {
525598
*(jlong *) dst = *(const jlong *) src;

0 commit comments

Comments
 (0)