Skip to content

Expand TLS access inline for Apple platforms - #133050

Draft
EgorBo wants to merge 2 commits into
dotnet:mainfrom
EgorBo:EgorBo/apple-inline-tls
Draft

Expand TLS access inline for Apple platforms#133050
EgorBo wants to merge 2 commits into
dotnet:mainfrom
EgorBo:EgorBo/apple-inline-tls

Conversation

@EgorBo

@EgorBo EgorBo commented Sep 1, 2026

Copy link
Copy Markdown
Member

Fixes #133041. (mostly just AI, to see if it passes CI)

On Apple targets the JIT emitted a call to dyld's tlv_get_addr thunk to obtain the address of t_ThreadStatics. Inline its fast path instead, like the other 64-bit targets already do.

The VM derives the pthread TSD key of coreclr's thread local block from the TLV descriptor, plus the offset of t_ThreadStatics within that block (folded into offsetOfBaseOfThreadLocalData), and passes the key to the JIT in the new tlsPthreadKey field. The derived offset must exactly match the descriptor's offset field in one of the two layouts dyld has shipped; if anything does not check out, tlsPthreadKey stays 0 and the JIT keeps calling the thunk.

[ThreadStatic] static int _tls1;
    
public int IntTls() => _tls1;
 ; Assembly listing for method MyBench:IntTls():int:this (Tier1)
 ; Emitting BLENDED_CODE for arm64 on Apple
 ; Tier1 code
 ; optimized code
 ; optimized using Synthesized PGO
 ; fp based frame
 ; partially interruptible
 ; with Synthesized PGO: fgCalledCount is 100
 ; No PGO data
 G_M000_IG01:                ;; offset=0x0000
             stp     fp, lr, [sp, #-0x10]!
             mov     fp, sp
 G_M000_IG02:                ;; offset=0x0008
-            movz    x0, #0xAFE0
-            movk    x0, #823 LSL #16
-            movk    x0, #1 LSL #32
-            movz    x1, #0xAFE0
-            movk    x1, #823 LSL #16
-            movk    x1, #1 LSL #32
-            ldr     x1, [x1]
-            blr     x1 ;; <-- call 
-            add     x0, x0, #60
+            mrs     x0, tpidrro_el0
+            and     x0, x0, #-8
+            ldr     x0, [x0, #0x810]
+            add     x0, x0, #356
             ldr     w0, [x0, #0x10]
-G_M000_IG03:                ;; offset=0x0030
+G_M000_IG03:                ;; offset=0x001C
             ldp     fp, lr, [sp], #0x10
             ret     lr
-; Total bytes of code 56
+; Total bytes of code 36

x64mov rax, gs:[key*8], reusing the existing FLD_GLOBAL_GS codegen.

Notes

  • Like the Windows and Linux expansions, the inlined sequence has no null check. Threads can only run managed code once attached, and attaching touches coreclr's __thread state through the thunk, which instantiates the block. The invariant is written down in helperexpansion.cpp.
  • NativeAOT is unaffected: inlined thread statics are gated to Linux/Windows x64+arm64 (ILCompiler/Program.cs), so fgExpandThreadLocalAccessForCallNativeAOT is not reachable on Apple. Enabling them there needs TLV section/reloc support in MachObjectWriter first, and would use the thunk rather than this inline sequence (the key is only known at load time).

On Apple targets the JIT called dyld's `tlv_get_addr` thunk to get the
address of `t_ThreadStatics`. Inline its fast path instead, like the
other 64-bit targets do.

The VM derives the pthread TSD key of coreclr's thread local block from
the TLV descriptor and the offset of `t_ThreadStatics` within that block,
validates them against the descriptor, and passes the key to the JIT in
the new `tlsPthreadKey` field. If anything does not check out the key
stays 0 and the JIT keeps calling the thunk.

arm64:
    mrs xd, tpidrro_el0
    and xd, xd, #~7
    ldr xd, [xd, #key * 8]
x64:
    mov xd, gs:[key * 8]

Fixes dotnet#133041

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Sep 1, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).
10 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@EgorBo

EgorBo commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

@EgorBot -macos_arm --envvars DOTNET_JitDisasm:IntTls

using BenchmarkDotNet.Attributes;

public class MyBench
{
    [ThreadStatic] static int _tls1;
    [ThreadStatic] static string _tls2;

    [Benchmark] public int IntTls() => _tls1;
    [Benchmark] public string StringTls() => _tls2;
}

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging @dotnet/jit-contrib for JIT-EE GUID update

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The cache publication has a C++ data race, and the intended Apple code generation lacks automated coverage.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Optimizes CoreCLR thread-static access on Apple x64/arm64 by bypassing dyld’s TLS thunk when its descriptor can be safely validated.

Changes:

  • Derives and caches the pthread TSD key and thread-static offset.
  • Emits direct GS/TPIDRRO TLS loads with thunk fallback.
  • Extends JIT-EE and SuperPMI structures and updates versioning.
File summaries
File Description
src/coreclr/vm/threadstatics.cpp Discovers and caches Apple TLS metadata.
src/coreclr/jit/helperexpansion.cpp Selects direct Apple TLS access.
src/coreclr/jit/emitarm64.cpp Emits TPIDRRO-based loads.
src/coreclr/jit/codegenarm64.cpp Guards Apple TLS-handle handling.
src/coreclr/jit/instrsarm64.h Defines the TPIDRRO instruction.
src/coreclr/inc/corinfo.h Adds the pthread key field.
src/coreclr/inc/jiteeversionguid.h Updates JIT-EE versioning.
src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs Mirrors the field for managed tooling.
src/coreclr/tools/superpmi/superpmi-shared/agnostic.h Extends the serialized structure.
src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp Records, dumps, and replays the key.
Review details
  • Files reviewed: 10/10 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread src/coreclr/vm/threadstatics.cpp Outdated
Comment thread src/coreclr/jit/helperexpansion.cpp
Address PR feedback: the payload was published with plain writes behind a
volatile flag, which is a data race between racing initializers. Use
Volatile<T> so all accesses are atomic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EgorBo
EgorBo force-pushed the EgorBo/apple-inline-tls branch from 97e380b to cf7b38c Compare September 2, 2026 00:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expand TLS access for macos-arm64

2 participants