-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[RyuJIT Wasm] Add Object Writer Imports Section + Constant Exprs to Encode R2R Payload Placement #123739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
adamperlin
wants to merge
3
commits into
dotnet:main
Choose a base branch
from
adamperlin:adamperlin/wasm-object-writer-imports
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+316
−33
Open
[RyuJIT Wasm] Add Object Writer Imports Section + Constant Exprs to Encode R2R Payload Placement #123739
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,12 @@ | |
|
|
||
| namespace ILCompiler.ObjectWriter | ||
| { | ||
| public interface IWasmEncodable | ||
| { | ||
| int EncodeSize(); | ||
| int Encode(Span<byte> buffer); | ||
| } | ||
|
|
||
| public enum WasmSectionType | ||
| { | ||
| Custom = 0, | ||
|
|
@@ -51,6 +57,12 @@ public enum WasmValueType : byte | |
| F64 = 0x7C | ||
| } | ||
|
|
||
| public enum WasmMutabilityType : byte | ||
| { | ||
| Const = 0x00, | ||
| Mut = 0x01 | ||
| } | ||
|
|
||
| public static class WasmValueTypeExtensions | ||
| { | ||
| public static string ToTypeString(this WasmValueType valueType) | ||
|
|
@@ -66,7 +78,7 @@ public static string ToTypeString(this WasmValueType valueType) | |
| } | ||
| } | ||
|
|
||
| #nullable enable | ||
| #nullable enable | ||
| public readonly struct WasmResultType : IEquatable<WasmResultType> | ||
| { | ||
| private readonly WasmValueType[] _types; | ||
|
|
@@ -150,15 +162,15 @@ public readonly int Encode(Span<byte> buffer) | |
| buffer[0] = 0x60; // function type indicator | ||
|
|
||
| int paramSize = _params.Encode(buffer.Slice(1)); | ||
| int returnSize = _returns.Encode(buffer.Slice(1+paramSize)); | ||
| int returnSize = _returns.Encode(buffer.Slice(1 + paramSize)); | ||
| Debug.Assert(totalSize == 1 + paramSize + returnSize); | ||
|
|
||
| return totalSize; | ||
| } | ||
|
|
||
| public bool Equals(WasmFuncType other) | ||
| { | ||
| return _params.Equals(other._params) && _returns.Equals(other._returns); | ||
| return _params.Equals(other._params) && _returns.Equals(other._returns); | ||
| } | ||
|
|
||
| public override bool Equals(object? obj) | ||
|
|
@@ -183,44 +195,255 @@ public override string ToString() | |
| } | ||
|
|
||
| // Represents a WebAssembly expression used in simple contexts for address calculation | ||
| enum WasmExprKind | ||
| public enum WasmExprKind | ||
| { | ||
| I32Const = 0x41, | ||
| I64Const = 0x42 | ||
| I64Const = 0x42, | ||
| GlobalGet = 0x23, | ||
| I32Add = 0x6A, | ||
| } | ||
|
|
||
| public static class WasmExprKindExtensions | ||
| { | ||
| public static bool IsConstExpr(this WasmExprKind kind) | ||
| { | ||
| return kind == WasmExprKind.I32Const || kind == WasmExprKind.I64Const; | ||
| } | ||
|
|
||
| public static bool IsBinaryExpr(this WasmExprKind kind) | ||
| { | ||
| return kind == WasmExprKind.I32Add; | ||
| } | ||
|
|
||
| public static bool IsGlobalVarExpr(this WasmExprKind kind) | ||
| { | ||
| return kind == WasmExprKind.GlobalGet; | ||
| } | ||
| } | ||
|
|
||
| class WasmInstructionGroup : IWasmEncodable | ||
| { | ||
| readonly WasmExpr[] WasmExprs; | ||
| public WasmInstructionGroup(WasmExpr[] wasmExprs) | ||
| { | ||
| WasmExprs = wasmExprs; | ||
| } | ||
|
|
||
| public int Encode(Span<byte> buffer) | ||
| { | ||
| int pos = 0; | ||
| foreach (var expr in WasmExprs) | ||
| { | ||
| pos += expr.Encode(buffer.Slice(pos)); | ||
| } | ||
| buffer[pos++] = 0x0B; // end opcode | ||
| return pos; | ||
| } | ||
|
|
||
| public int EncodeSize() | ||
| { | ||
| int size = 0; | ||
| foreach (var expr in WasmExprs) | ||
| { | ||
| size += expr.EncodeSize(); | ||
| } | ||
| // plus one for the end opcode | ||
| return size + 1; | ||
| } | ||
| } | ||
|
|
||
| class WasmConstExpr | ||
| public abstract class WasmExpr : IWasmEncodable | ||
| { | ||
| WasmExprKind _kind; | ||
| public WasmExpr(WasmExprKind kind) | ||
| { | ||
| _kind = kind; | ||
| } | ||
|
|
||
| public virtual int EncodeSize() => 1; | ||
| public virtual int Encode(Span<byte> buffer) | ||
| { | ||
| buffer[0] = (byte)_kind; | ||
| return 1; | ||
| } | ||
| } | ||
|
|
||
| class WasmConstExpr : WasmExpr | ||
| { | ||
| long ConstValue; | ||
|
|
||
| public WasmConstExpr(WasmExprKind kind, long value) | ||
| public WasmConstExpr(WasmExprKind kind, long value) : base(kind) | ||
| { | ||
| if (kind == WasmExprKind.I32Const) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfGreaterThan(value, int.MaxValue); | ||
| ArgumentOutOfRangeException.ThrowIfLessThan(value, int.MinValue); | ||
| } | ||
|
|
||
| _kind = kind; | ||
| ConstValue = value; | ||
| } | ||
|
|
||
| public int EncodeSize() | ||
| public override int EncodeSize() | ||
| { | ||
| uint valSize = DwarfHelper.SizeOfSLEB128(ConstValue); | ||
| return 1 + (int)valSize + 1; // opcode + value + end opcode | ||
| uint valSize = DwarfHelper.SizeOfSLEB128(ConstValue); | ||
| return base.EncodeSize() + (int)valSize; | ||
| } | ||
|
|
||
| public int Encode(Span<byte> buffer) | ||
| public override int Encode(Span<byte> buffer) | ||
| { | ||
| int pos = 0; | ||
| buffer[pos++] = (byte)_kind; // the kind is the opcode, either i32.const or i64.const | ||
|
|
||
| int pos = base.Encode(buffer); | ||
| pos += DwarfHelper.WriteSLEB128(buffer.Slice(pos), ConstValue); | ||
|
|
||
| buffer[pos++] = 0x0B; // end opcode | ||
| return pos; | ||
| } | ||
| } | ||
|
|
||
| // Simple DSL wrapper for creating Wasm expressions | ||
| static class Global | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please put the DSL in a namespace of its own |
||
| { | ||
| public static WasmExpr Get(int index) | ||
| { | ||
| return new WasmGlobalVarExpr(WasmExprKind.GlobalGet, index); | ||
| } | ||
| } | ||
|
|
||
| static class I32 | ||
| { | ||
| public static WasmExpr Const(long value) | ||
| { | ||
| return new WasmConstExpr(WasmExprKind.I32Const, value); | ||
| } | ||
|
|
||
| public static WasmExpr Add => new WasmBinaryExpr(WasmExprKind.I32Add); | ||
| } | ||
|
|
||
| class WasmGlobalVarExpr : WasmExpr | ||
| { | ||
| public readonly int GlobalIndex; | ||
| public WasmGlobalVarExpr(WasmExprKind kind, int globalIndex) : base(kind) | ||
| { | ||
| Debug.Assert(globalIndex >= 0); | ||
| Debug.Assert(kind.IsGlobalVarExpr()); | ||
| GlobalIndex = globalIndex; | ||
| } | ||
|
|
||
| public override int Encode(Span<byte> buffer) | ||
| { | ||
| int pos = base.Encode(buffer); | ||
| pos += DwarfHelper.WriteULEB128(buffer.Slice(pos), (uint)GlobalIndex); | ||
| return pos; | ||
| } | ||
|
|
||
| public override int EncodeSize() | ||
| { | ||
| return base.EncodeSize() + (int)DwarfHelper.SizeOfULEB128((uint)GlobalIndex); | ||
| } | ||
| } | ||
|
|
||
| // Represents a binary expression (e.g., i32.add) | ||
| class WasmBinaryExpr : WasmExpr | ||
| { | ||
| public WasmBinaryExpr(WasmExprKind kind) : base(kind) | ||
| { | ||
| Debug.Assert(kind.IsBinaryExpr()); | ||
| } | ||
|
|
||
| // base class defaults are sufficient as the base class encodes just the opcode | ||
| } | ||
| public abstract class WasmImportType : IWasmEncodable | ||
| { | ||
| public abstract int Encode(Span<byte> buffer); | ||
| public abstract int EncodeSize(); | ||
| } | ||
|
|
||
|
|
||
| public enum WasmExternalKind : byte | ||
| { | ||
| Function = 0x00, | ||
| Table = 0x01, | ||
| Memory = 0x02, | ||
| Global = 0x03, | ||
| Tag = 0x04 | ||
| } | ||
|
|
||
| public class WasmGlobalType : WasmImportType | ||
| { | ||
| WasmValueType ValueType; | ||
| WasmMutabilityType Mutability; | ||
|
|
||
| public WasmGlobalType(WasmValueType valueType, WasmMutabilityType mutability) | ||
| { | ||
| ValueType = valueType; | ||
| Mutability = mutability; | ||
| } | ||
|
|
||
| public override int Encode(Span<byte> buffer) | ||
| { | ||
| buffer[0] = (byte)ValueType; | ||
| buffer[1] = (byte)Mutability; | ||
| return 2; | ||
| } | ||
|
|
||
| public override int EncodeSize() => 2; | ||
| } | ||
|
|
||
| public enum WasmLimitType : byte | ||
| { | ||
| HasMin = 0x00, | ||
| HasMinAndMax = 0x01 | ||
| } | ||
|
|
||
| public class WasmMemoryType : WasmImportType | ||
| { | ||
| WasmLimitType LimitType; | ||
| uint Min; | ||
| uint? Max; | ||
|
|
||
| public WasmMemoryType(WasmLimitType limitType, uint min, uint? max = null) | ||
| { | ||
| if (LimitType == WasmLimitType.HasMinAndMax && !Max.HasValue) | ||
| { | ||
| throw new ArgumentException("Max must be provided when LimitType is HasMinAndMax"); | ||
| } | ||
|
|
||
| LimitType = limitType; | ||
| Min = min; | ||
| Max = max; | ||
| } | ||
|
|
||
| public override int Encode(Span<byte> buffer) | ||
| { | ||
| int pos = 0; | ||
| buffer[pos++] = (byte)LimitType; | ||
| pos += DwarfHelper.WriteULEB128(buffer.Slice(pos), Min); | ||
| if (LimitType == WasmLimitType.HasMinAndMax) | ||
| { | ||
| pos += DwarfHelper.WriteULEB128(buffer.Slice(pos), Max!.Value); | ||
| } | ||
| return pos; | ||
| } | ||
|
|
||
| public override int EncodeSize() => 2; | ||
| } | ||
adamperlin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| public class WasmImport : IWasmEncodable | ||
| { | ||
| public string Module; | ||
| public string Name; | ||
| public WasmExternalKind Kind; | ||
| WasmImportType Import; | ||
|
|
||
| public WasmImport(string module, string name, WasmExternalKind kind, WasmImportType import) | ||
| { | ||
| Module = module; | ||
| Name = name; | ||
| Kind = kind; | ||
| Import = import; | ||
| } | ||
|
|
||
| public int Encode(Span<byte> buffer) => Import.Encode(buffer); | ||
| public int EncodeSize() => Import.EncodeSize(); | ||
|
|
||
| #nullable disable | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.