Skip to content

[crossgen2][wasm] Shrink Code Section Relocs - #132029

Draft
adamperlin wants to merge 5 commits into
dotnet:mainfrom
adamperlin:adamperlin/wasm-object-writer-shrink-relocs
Draft

[crossgen2][wasm] Shrink Code Section Relocs#132029
adamperlin wants to merge 5 commits into
dotnet:mainfrom
adamperlin:adamperlin/wasm-object-writer-shrink-relocs

Conversation

@adamperlin

@adamperlin adamperlin commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

This PR implements a relocation shrinking optimization in the WasmObjectWriter. All relocations in Wasm code emitted by the JIT are currently padded to the max 32-bit ULEB length of 5 bytes, but their resolved values may be much shorter. This PR keeps behavior the same for non-code sections which don't have variable length relocs, while implementing a shrinking procedure to re-write each relocation in the code section to its minimal length. The LEB lengths of each code blob are updated accordingly after shrinkage.

This yields around 5% size savings for System.Private.CoreLib.

Copilot AI lite review requested due to automatic review settings August 8, 2026 00:09
@adamperlin adamperlin changed the title [crossgen2] [wasm] Shrink Code Section Relocs [crossgen2][wasm] Shrink Code Section Relocs Aug 8, 2026
@azure-pipelines

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

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.

Pull request overview

This PR updates the CoreCLR Wasm object writer to support shrinking variable-length relocations in the Wasm code section, reducing output size by rewriting padded LEB relocations to their minimal encoded lengths and updating code-blob length prefixes accordingly.

Changes:

  • Refactors relocation resolution to support a source→destination stream flow, enabling in-place rewriting for shrinkable code blobs.
  • Adds code-section-specific parsing and rewriting of length-prefixed code blobs to shrink variable-length relocations and update blob sizes.
  • Introduces helper APIs for stream-based ULEB128 decoding and variable-length relocation writing.

Reviewed changes

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

File Description
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Adds code-section relocation shrinking logic and refactors relocation resolution to support rewriting into a destination stream.
src/coreclr/tools/Common/Compiler/ObjectWriter/Dwarf/DwarfHelper.cs Adds a stream-based ULEB128 reader used by code-blob parsing.
src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs Adds helpers to detect variable-length Wasm relocations and write minimally-sized LEB encodings.
Suppressed comments (1)

src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs:734

  • Unused local sectionStream is created but never used; this is dead code and will trigger an unnecessary-using/unused-variable warning. Remove it (the relocation resolution already copies from section.Stream into webcilStream).
                    MemoryStream sectionStream = new MemoryStream((int)section.Stream.Length);

Comment on lines +1211 to 1219
long startPos = dstStream.Position;
sectionStream.CopyTo(dstStream);
for (int i = 0; i < relocs.Count; i++)
{
sectionStream.Position = reloc.Offset + sectionStart;
sectionStream.Write(new Span<byte>(pData, Relocation.GetSize(reloc.Type)));
SymbolicRelocation reloc = relocs[i];
ResolveReloc(sectionIndex, dstStream, srcPos: sectionStart + reloc.Offset, dstStream, destPos: sectionStart + reloc.Offset, reloc, relocScratchBuffer);
}
dstStream.Position = sectionStream.Length + startPos;
}
Comment on lines +126 to +149
public static ulong? ReadULEB128(Stream source, out int bytesRead)
{
ulong value = 0;
byte @byte;
int shift = 0;
long startPos = source.Position;

do
{
int b = source.ReadByte();
if (b < 0)
{
bytesRead = (int)(source.Position - startPos);
return null;
}

@byte = (byte)b;
value |= ((ulong)@byte & 0x7f) << shift;
shift += 7;
} while ((@byte & 0x80) != 0);

bytesRead = (int)(source.Position - startPos);
return value;
}
src.GetBuffer().AsSpan((int)srcPos, (int)count).CopyTo(dest.GetBuffer().AsSpan((int)destPos, (int)count));
}

private record CodeBlob(long Size, long Start, long End);
Comment on lines 4 to 8
using System;
using System.Diagnostics;
using System.Runtime.Serialization;
using ILCompiler.ObjectWriter;

Comment on lines 4 to 9
using System;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants