Skip to content

Support /OPTIMIZE and raw method-body emission in managed ilasm - #135136

Open
jkoritzinsky wants to merge 2 commits into
dotnet:mainfrom
jkoritzinsky:jkoritzinsky-managed-ilasm-optimization
Open

jkoritzinsky wants to merge 2 commits into
dotnet:mainfrom
jkoritzinsky:jkoritzinsky-managed-ilasm-optimization

Conversation

@jkoritzinsky

Copy link
Copy Markdown
Member

Motivation

Managed ilasm currently ignores /OPTIMIZE: integer-constant helpers compact instructions regardless of the option, while SRM's control-flow encoders cannot preserve some intentionally malformed offsets. This prevents byte-faithful assembly and limits the invalid IL that error-tolerant runtime tests can generate.

Approach

  • Preserve authored long, short, and macro instruction forms by default. With /OPTIMIZE, select compact constant and argument/local encodings and apply native ilasm's numeric/known-target branch policy.
  • Introduce a local method-body writer with signed-offset labels and reserved-operand fixups. Reuse SRM's size-based method-body API for headers, while emitting instruction bytes and exception clauses directly.
  • Retain negative and past-end raw EH bounds under /ERROR, with source-located diagnostics, rather than dropping exception tables. Numeric branch/switch operands remain verbatim even when they target bytes outside the code.
  • Correct long argument/local operands from four bytes to two. Preserve deferred metadata-token resolution and emitted-code offsets in portable PDB sequence points, including global methods.
  • Remove the private framework label accessor and the fixed-capacity chunk-boundary workaround.

Forward long branches are not relaxed. Explicit .s branches are never widened; overflowing operands are diagnosed, and error-tolerant output retains their truncated bytes. Raw numeric EH bounds remain absolute and are not relocated when optimization changes instruction sizes.

Validation

Windows x64:

  • dotnet.cmd build src\tools\ilasm\ilasm.slnx passed, including NativeAOT publication.
  • All 520 tests passed, with zero failures or skips, including 114 added cases. Coverage checks exact instruction bytes, branch limits, switch bases, malformed EH fields, small/fat layouts, builder chunks, resolved tokens, global methods, and decoded PDB offsets.
  • Ten CLI smoke images verified all optimization aliases, an explicit false option, strict-mode rejection, and error-tolerant malformed EH output. Representative instruction and EH bytes matched native ilasm built from this checkout.

Assembler overhead measurements

Baseline and changed Release libraries were measured with the same branch-heavy input using BenchmarkDotNet 0.15.8 on Windows x64/.NET 11 RC, with three warmups and eight measured iterations.

Branches Baseline mean Changed mean Baseline allocated Changed allocated
8 150.8 us 110.2 us 207.95 KB 203.57 KB
1,024 10.222 ms 9.317 ms 5,970.65 KB 6,058.88 KB

These in-process measurements on a Hyper-V VM are exploratory, not a throughput-improvement claim. No mean throughput regression was observed; the large case allocates about 1.5% more for source-located fixup bookkeeping.

Note

This change and pull request description were prepared with GitHub Copilot.

Preserve authored instruction forms by default and select compact encodings only with /OPTIMIZE. Use a local method-body writer for branch fixups and raw exception clauses, retaining malformed offsets in error-tolerant output. Correct long variable operands and cover instruction, layout, diagnostic, and PDB behavior with exact-output tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @dotnet/jit-contrib
See info in area-owners.md if you want to be subscribed.

Resolve the visitor deletion by integrating raw instruction emission and method finalization with upstream ANTLR actions. Preserve native-compatible fat-header handling, assign non-conflicting diagnostic IDs, and retain upstream tests while adapting malformed-EH and source-span assertions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jkotas
jkotas requested a balanced review from Copilot October 2, 2026 23:17
@jkotas

jkotas commented Oct 2, 2026

Copy link
Copy Markdown
Member

There are still unresolved conflicts

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.

Copilot review overview

🟡 Changes recommended

Zero-code methods still bypass body emission and drop authored malformed exception regions.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Adds byte-faithful managed ilasm emission, optional instruction optimization, branch fixups, and malformed EH preservation.

Changes:

  • Introduces a custom method-body writer with branch, switch, token, and EH fixups.
  • Implements /OPTIMIZE instruction selection and new diagnostics.
  • Adds extensive encoding, EH, and PDB tests.
File Description
SourceDirectiveTests.cs Tests optimized PDB offsets.
InstructionTests.cs Tests instruction encodings and fixups.
ExceptionHandlingTests.cs Tests raw and optimized EH emission.
DocumentCompilerTestHelpers.cs Adds compilation and IL helpers.
Options.cs Documents optimization behavior.
MethodBodyWriter.cs Implements raw method-body emission.
InstructionEncoderExtensions.cs Removes private SRM accessor.
EntityRegistry.cs Integrates the new writer.
Diagnostic.cs Adds branch and EH diagnostics.
GrammarActions.MethodBodies.ExceptionHandling.cs Records EH locations and labels.
GrammarActions.MethodBodies.cs Completes fixups at method end.
GrammarActions.Instructions.cs Routes instruction emission through the writer.
GrammarActions.Conversions.cs Marks new diagnostics recoverable.
KNOWN-ISSUES.md Removes the obsolete optimization limitation.

Comment on lines +370 to +371
bodyOffset = methodDef.MethodBody.WriteTo(bodyStreamEncoder, methodDef.MaxStack,
localsSigHandle, bodyAttributes, methodDef.ExceptionRegions, hasDynamicStackAllocation: true);
if (optimize && _labels[target.Id - 1] is int targetOffset)
{
long distance = (long)targetOffset - Offset;
// Native ilasm uses the worst-case long-instruction size when shortening a known target.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can this comment be rephrased without referring to native ilasm?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants