1313#include < type_traits>
1414#include " codeCache.h"
1515#include " safeAccess.h"
16+ #include " thread.h"
1617#include " threadState.h"
1718#include " vmEntry.h"
1819
@@ -539,6 +540,21 @@ DECLARE(VMThread)
539540 (vtbl[5 ] == _java_thread_vtbl[5 ]) >= 2 ;
540541 }
541542
543+ // Cached version of isJavaThread(). On first call per thread, computes the
544+ // vtable check and caches the result in ProfiledThread for O(1) subsequent
545+ // lookups. This is needed because JVMTI ThreadStart only fires for application
546+ // threads, not for JVM-internal JavaThread subclasses (CompilerThread, etc.).
547+ bool cachedIsJavaThread () {
548+ ProfiledThread* pt = ProfiledThread::currentSignalSafe ();
549+ if (pt != NULL ) {
550+ if (!pt->isJavaThreadKnown ()) {
551+ pt->cacheJavaThread (isJavaThread ());
552+ }
553+ return pt->isJavaThread ();
554+ }
555+ return isJavaThread ();
556+ }
557+
542558 OSThreadState osThreadState ();
543559
544560 int state ();
@@ -548,16 +564,34 @@ DECLARE(VMThread)
548564 }
549565
550566 bool inDeopt () {
567+ if (!cachedIsJavaThread ()) return false ;
551568 assert (_thread_vframe_offset >= 0 );
552569 return SafeAccess::loadPtr ((void **) at (_thread_vframe_offset), nullptr ) != NULL ;
553570 }
554571
572+ // Check if the thread object memory is readable up to the largest used
573+ // offset. On some JVMs (e.g. GraalVM 25 aarch64), a wall-clock signal
574+ // can hit a thread whose memory is only partially mapped — the vtable
575+ // at offset 0 may be readable while fields deeper in the object are not.
576+ // On non-HotSpot JVMs (J9, Zing) offsets stay at -1; skip the check.
577+ bool isThreadAccessible () {
578+ int max_offset = -1 ;
579+ if (_thread_exception_offset > max_offset) max_offset = _thread_exception_offset;
580+ if (_thread_state_offset > max_offset) max_offset = _thread_state_offset;
581+ if (_thread_osthread_offset > max_offset) max_offset = _thread_osthread_offset;
582+ if (_thread_anchor_offset > max_offset) max_offset = _thread_anchor_offset;
583+ if (_thread_vframe_offset > max_offset) max_offset = _thread_vframe_offset;
584+ if (max_offset < 0 ) return true ;
585+ return SafeAccess::isReadableRange (this , max_offset + sizeof (void *));
586+ }
587+
555588 void *& exception () {
556589 assert (_thread_exception_offset >= 0 );
557590 return *(void **) at (_thread_exception_offset);
558591 }
559592
560593 VMJavaFrameAnchor* anchor () {
594+ if (!cachedIsJavaThread ()) return NULL ;
561595 assert (_thread_anchor_offset >= 0 );
562596 return VMJavaFrameAnchor::cast (at (_thread_anchor_offset));
563597 }
0 commit comments