From cca54f5abb13c296834e9f21e087acfa1b95aa49 Mon Sep 17 00:00:00 2001 From: "Enzo Persillet (Tutez)" Date: Thu, 5 Nov 2026 19:45:17 +0100 Subject: [PATCH] Read the GC's thread context from a __thread pointer on Linux On Linux the fast thread-local slot, the GC's stack context, was read with pthread_getspecific: a call through the PLT on each allocation that leaves the inline path, each time a String or a number is boxed, and wherever HX_CTX_GET is used. In an OpenFL game it was 3 to 4% of the main thread's samples. With GCC and Clang on Linux it is now a __thread pointer, read with one load from the thread pointer. __thread rather than thread_local: for an extern thread_local, C++ calls a wrapper in case another unit initializes it dynamically. Defining HXCPP_PTHREAD_FAST_TLS keeps pthread_getspecific. Co-Authored-By: Claude Opus 5.5 --- include/hx/Tls.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/hx/Tls.h b/include/hx/Tls.h index be79045c..db1409a4 100755 --- a/include/hx/Tls.h +++ b/include/hx/Tls.h @@ -144,6 +144,22 @@ struct TLSData #define EXTERN_FAST_TLS_DATA(TYPE,NAME) \ __declspec(thread) extern TYPE * NAME; +#elif defined(HX_LINUX) && defined(__GNUC__) && !defined(HXCPP_PTHREAD_FAST_TLS) + +// The fast slot (the GC's stack context, read on each allocation that leaves +// the inline path) is a plain thread-local pointer: one load from the thread +// pointer instead of a call to pthread_getspecific. __thread rather than +// thread_local, so the extern declaration reads it directly instead of +// calling the wrapper C++ emits in case of a dynamic initializer. +#define DECLARE_TLS_DATA(TYPE,NAME) \ + ::hx::TLSData NAME; +#define DECLARE_FAST_TLS_DATA(TYPE,NAME) \ + __thread TYPE * NAME = nullptr; +#define EXTERN_TLS_DATA(TYPE,NAME) \ + extern ::hx::TLSData NAME; +#define EXTERN_FAST_TLS_DATA(TYPE,NAME) \ + extern __thread TYPE * NAME; + #else #define DECLARE_TLS_DATA(TYPE,NAME) \