Skip to content

Implement computed goto dispatch for the CoreCLR interpreter - #129216

Merged
BrzVlad merged 6 commits into
dotnet:mainfrom
BrzVlad:feature-clrinterp-computed-goto
Jun 23, 2026
Merged

Implement computed goto dispatch for the CoreCLR interpreter#129216
BrzVlad merged 6 commits into
dotnet:mainfrom
BrzVlad:feature-clrinterp-computed-goto

Conversation

@BrzVlad

@BrzVladBrzVlad commented Jun 10, 2026

Copy link
Copy Markdown
Member

Instead of making each opcode dispatch to the loop start where we switch on the opcode, we transform every switch case into a label, we let the compiler statically populate the s_dispatchTable which maps each opcode to the label address. This makes opcode dispatch a simple load + branch to the label address from this table. This makes the interpreter 25% faster.

It is unclear whether this has any impact on wasm. Likely not, because wasm has control flow limitations that make random branches impossible.

As an additional optimization, we avoid saving pFrame->ip for each opcode. Removing this can improve execution speed by around 3%. Instead we explicitly save pFrame->ip in opcodes that can trigger GC or throw exception. Add InterpThrow helper to ensure pFrame->ip is set before all throws.

CopilotAI review requested due to automatic review settings June 10, 2026 05:43
@BrzVlad
BrzVlad requested review from janvorli and kg as code ownersJune 10, 2026 05:43

CopilotAI 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.

Copilot wasn't able to review any files in this pull request.

@BrzVlad

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-interpreter

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@BrzVlad

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-interpreter

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas added the tenet-performance Performance related issue label Jun 10, 2026
@BrzVlad

Copy link
Copy Markdown
MemberAuthor

Assembly before

// INTOP_NEXT
0x105260a0c: ldr w23, [x28, #0xc]! // x28 = ip, load the next opcode
0x105260a10: cmp w23, #0x15f // check for the default branch
0x105260a14: b.ls 0x10525e034
0x105260a18: b 0x10526295c
// Loop start
0x10525e034: mov w8, w23
0x10525e038: adrp x11, 414 // rather long switch dispatch
0x10525e03c: add x11, x11, #0x624
0x10525e040: adr x9, 0x10525e008
0x10525e044: ldrh w10, [x11, x8, lsl #1]
0x10525e048: add x9, x9, x10, lsl #2
0x10525e04c: br x9

Assembly after

// INTOP_NEXT
0x1051f63e0: ldr w23, [x27, #0x8]! // x27 = ip, load the next opcode
0x1051f63e4: ldr x8, [x22, x23, lsl #3] // x22 = s_dispatchTable, load label of next
0x1051f63e8: br x8 // dispatch

Instead of making each opcode dispatch to the loop start where we switch on the opcode, we transform every switch case into a label, we let the compiler statically populate the s_dispatchTable which maps each opcode to the label address. This makes opcode dispatch a simple load + branch to the label address from this table. This makes the interpreter 25% faster.
It is unclear whether this has any impact on wasm. Likely not, because wasm has control flow limitations that make random branches impossible.
Removing this can improve execution speed by around 3%. Instead we explicitly save pFrame->ip in opcodes that can trigger GC or throw exception. Add InterpThrow helper to ensure pFrame->ip is set before all throws.
@BrzVlad
BrzVladforce-pushed the feature-clrinterp-computed-goto branch from 1f2bd0a to e39e619CompareJune 17, 2026 15:43
@BrzVlad

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-interpreter
/azp run runtime-libraries-interpreter

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@BrzVlad

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-interpreter

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@BrzVlad

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-interpreter

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI review requested due to automatic review settings June 18, 2026 12:20

CopilotAI 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.

Pull request overview

Copilot reviewed 1 out of 2 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/vm/interpexec.cpp
Comment threadsrc/coreclr/vm/interpexec.cpp
Comment threadsrc/coreclr/interpreter/inc/intops.def
@BrzVlad

Copy link
Copy Markdown
MemberAuthor

/ba-g unrelated timeouts in non-interpreter jobs

@BrzVlad
BrzVlad requested a review from janvorliJune 18, 2026 20:10
Comment threadsrc/coreclr/interpreter/inc/intops.def
Comment threadsrc/coreclr/vm/interpexec.cpp Outdated
We disable this on windows where vc compiler doesn't supported it.
If we ever get to interpreting an invalid opcode, the most likely value would be 0. Having this opcode do random operations (like returning from the frame as it was the case before with INTOP_RET having the 0 value) could make it harder to diagnose this types of bugs if they will ever appear in the future. On mono we've had multiple cases where we were trying to execute code from invalid memory, hitting this case.
@BrzVlad

Copy link
Copy Markdown
MemberAuthor

Could I get a final review on this ? @janvorli your previous review got stale after a rebase.

@BrzVlad

Copy link
Copy Markdown
MemberAuthor

/ba-g non-interpreter failures

@BrzVlad
BrzVlad merged commit 461fd2a into dotnet:mainJun 23, 2026
108 of 112 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 24, 2026
@am11am11 mentioned this pull request Jun 24, 2026
15 tasks
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Instead of making each opcode dispatch to the loop start where we switch
on the opcode, we transform every switch case into a label, we let the
compiler statically populate the s_dispatchTable which maps each opcode
to the label address. This makes opcode dispatch a simple load + branch
to the label address from this table. This makes the interpreter 25%
faster.
It is unclear whether this has any impact on wasm. Likely not, because
wasm has control flow limitations that make random branches impossible.
As an additional optimization, we avoid saving `pFrame->ip` for each
opcode. Removing this can improve execution speed by around 3%. Instead
we explicitly save `pFrame->ip` in opcodes that can trigger GC or throw
exception. Add InterpThrow helper to ensure `pFrame->ip` is set before
all throws.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 24, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@BrzVlad@am11@jkotas@janvorli