Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6695,13 +6695,14 @@ void MacroAssembler::java_round_float(Register dst, FloatRegister src,
// by the call to JavaThread::aarch64_get_thread_helper() or, indeed,
// the call setup code.
//
// On Linux, aarch64_get_thread_helper() clobbers only r0, r1, and flags.
// On Linux and Windows, aarch64_get_thread_helper() is implemented in
// assembly and clobbers only r0, r1, and flags.
// On other systems, the helper is a usual C function.
//
void MacroAssembler::get_thread(Register dst) {
RegSet saved_regs =
LINUX_ONLY(RegSet::range(r0, r1) + lr - dst)
NOT_LINUX (RegSet::range(r0, r17) + lr - dst);
BSD_ONLY(RegSet::range(r0, r17) + lr - dst)
NOT_BSD (RegSet::range(r0, r1) + lr - dst);

protect_return_address();
push(saved_regs, sp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
#include "runtime/frame.inline.hpp"
#include "runtime/javaThread.hpp"

#include <windows.h>

// CRT-provided TLS slot for this module (jvm.dll), set by the OS loader.
extern "C" unsigned long _tls_index;

// TLS offset read by the assembly code in `aarch64_get_thread_helper()`. This
// offset is initialized by `cache_global_variables()` before any JIT code.
extern "C" int64_t _jvm_thr_current_tls_offset = 0;

frame JavaThread::pd_last_frame() {
assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
vmassert(_anchor.last_Java_pc() != nullptr, "not walkable");
Expand Down Expand Up @@ -86,4 +95,21 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
return false;
}

void JavaThread::cache_global_variables() { }
void JavaThread::cache_global_variables() {
// 0x58 is the offset of ThreadLocalStoragePointer within the TEB. This is a
// stable Windows ABI constant but is not exposed in the SDK's minimal _TEB
// struct.
void** tls_array = *(void***)((char*)NtCurrentTeb() + 0x58);
char* tls_block = (char*)tls_array[_tls_index];

// Compute the offset of Thread::_thr_current within this module's TLS block.
// Unlike ELF, which provides `tlsdesc` relocations that let assembly resolve
// TLS variables symbolically at link/load time, Windows PE/COFF has no
// equivalent mechanism for armasm64. So we compute the offset here in C++
// (where the compiler knows how to access __declspec(thread) variables) and
// store it in a plain global that the assembly can load directly. In
// subsequent calls to `aarch64_get_thread_helper()`, the assembly will read
// the TEB to find the TLS block and then add this offset to find
// `Thread::_thr_current`.
_jvm_thr_current_tls_offset = (int64_t)((char*)&Thread::_thr_current - tls_block);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@
bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);
public:

static Thread *aarch64_get_thread_helper() {
return Thread::current();
}
static Thread *aarch64_get_thread_helper();

#endif // OS_CPU_WINDOWS_AARCH64_JAVATHREAD_WINDOWS_AARCH64_HPP
64 changes: 64 additions & 0 deletions src/hotspot/os_cpu/windows_aarch64/threadLS_windows_aarch64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
;
; Copyright (c) 2026, 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.
;

; JavaThread::aarch64_get_thread_helper()
;
; Optimized TLS access to `Thread::_thr_current` on Windows AArch64.
; Returns the current thread pointer in x0, clobbers x1, while all other
; registers are preserved.

IMPORT _tls_index
IMPORT _jvm_thr_current_tls_offset

AREA threadls_text, CODE, READONLY
ALIGN 4

; MSVC-decorated name for: static Thread* JavaThread::aarch64_get_thread_helper()
EXPORT |?aarch64_get_thread_helper@JavaThread@@SAPEAVThread@@XZ|

|?aarch64_get_thread_helper@JavaThread@@SAPEAVThread@@XZ| PROC

; x18 holds the TEB, 0x58 is a well-defined offset into the TEB on 64-bit
; systems, so the following line loads the thread-local storage pointer
; inside the TEB
ldr x1, [x18, #0x58]

; Load `_tls_index` and zero-extend it to 64 bits to occupy x0
ldr x0, =_tls_index
ldr w0, [x0]

; `x0` holds the index, `x1` holds the array base address (each entry is 64
; bits long), so in the following line, x1 = array_base[_tls_index]
ldr x1, [x1, x0, lsl #3]

; Load cached TLS offset of `Thread::_thr_current`
ldr x0, =_jvm_thr_current_tls_offset
ldr x0, [x0]

; Load `Thread::_thr_current` value
ldr x0, [x1, x0]

ret

ENDP
END
35 changes: 35 additions & 0 deletions test/hotspot/gtest/aarch64/test_threadLS.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2026, 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.
*/

#if defined(AARCH64) && !defined(ZERO)

#include "runtime/javaThread.hpp"
#include "unittest.hpp"

TEST_VM(ThreadLS, get_thread_helper) {
Thread* expected = Thread::current();
Thread* actual = JavaThread::aarch64_get_thread_helper();
ASSERT_EQ(actual, expected);
}

#endif // AARCH64 && !ZERO