Skip to content

Move custom attribute materialization and invocation to managed code - #133658

Draft
jkoritzinsky wants to merge 9 commits into
dev/jkoritzinsky/custom-attribute-stackfrom
dev/jkoritzinsky/custom-attribute-constructors
Draft

Move custom attribute materialization and invocation to managed code#133658
jkoritzinsky wants to merge 9 commits into
dev/jkoritzinsky/custom-attribute-stackfrom
dev/jkoritzinsky/custom-attribute-constructors

Conversation

@jkoritzinsky

@jkoritzinsky jkoritzinsky commented Sep 11, 2026

Copy link
Copy Markdown
Member

Summary

Layer 2 of the reflection → custom attributes → func-eval → cleanup stack for #123864, building on am11's work in #126542 and the requested split in #126542 (comment).

  • Move both CustomAttribute_CreateCustomAttributeInstance and CustomAttribute_CreatePropertyOrFieldData, including their exclusive blob/array decoding closure, into ordinary C#.
  • Reuse the bounded managed blob reader without constructing intermediate custom-attribute data graphs. Preserve scalar widths, enum identity, typed arrays, named-argument ordering, exception boundaries, and type-resolution behavior.
  • Keep fixed primitive/enum constructor arguments unboxed, with InlineArray16<T> storage, a bounded heap fallback, and explicit GC reporting for the byref vector. Box only where an object is required.
  • Resolve type names through the existing span-based resolver, preserving contextual-reflection and collectible-type rules.
  • Remove the obsolete materialization QCalls and temporary CA UCO bridge. Retain native CaArg/CaValue parsing and attribute-usage parsing.

Validation

Windows x64 Checked CoreCLR/Release libraries: live custom attributes, Reflection.Emit custom-attribute blobs, data-only reflection, and Reflection.Extensions coverage. Constructor/exception tests span the new 10,000-call promotion boundary. Coverage includes malformed/truncated blobs, enum widths, floating-point bits, moving GC, the 17-argument heap fallback, and collectible/contextual resolution. Forced shared and forced emitted invocation were also exercised.

Browser/WASI managed CoreLib and generated ABI inputs were checked; actual browser/WASI and big-endian runtime execution were not performed.

Performance evidence

Matched Release measurements compared managed decoding against a native-materialization baseline that already retained unboxed argument storage. On the local Windows x64 EPYC 7763 Hyper-V VM, warmed reference-argument, named-argument, array, and tagged-object cases measured approximately 0.73–0.82× the baseline time, with unchanged managed allocations. Fresh-process results were mixed and include parser/boxing-cache initialization; this is not a universal startup or cross-platform performance claim.

The next layers are #133659 (func-eval) and #133660 (dead native machinery cleanup).


Stack created with GitHub Stacks CLIGive Feedback 💬

Note

This PR description and implementation were prepared with GitHub Copilot. Commits that reuse am11's code retain the requested co-author attribution.

jkoritzinsky and others added 9 commits September 10, 2026 16:18
Port the custom-attribute layer of #126542 on top of shared reflection invocation. Keep argument parsing native, pass typed GC-protected constructor and argument references to one UCO entrypoint, and reuse MethodBaseInvoker. Preserve nulls, primitive and enum boxing, constructor exceptions, and platform-specific WASM callback tables.

Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the native GC root strongly typed while accounting for the different OBJECTREF representation in Checked and Release builds.

Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Avoid allocating an object array and boxing primitive arguments. Keep native value and GC-protected reference homes alive across UCO and use the shared MethodBaseInvoker byref path directly. Release comparison restores baseline allocations and removes the measured one-argument regression.

Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace both live custom-attribute materializing QCalls and their exclusive native reader closure with shared bounded C# decoding. Preserve unboxed fixed arguments, native CA type-resolution rules, typed arrays and sequential named assignments. Retain native CaArg/usage parsing and the data-only object model. Remove CA UCO/binder/WASM registrations and add baseline-characterized compatibility, GC and malformed-input coverage.

Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use the shared inline-array type for reference, primitive, and byref scratch buffers. Scope the stack argument limit to constructor materialization and rely on default initialization for the registered byref storage.

Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Return bounded raw data from the shared reader and consume spans directly for constructor storage, boxing, and primitive arrays. Preserve native byte order with span reversal instead of Unsafe value reinterpretation.

Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Qualify references outside CustomAttributeEncodedArgument with the enclosing type instead of a file-level alias.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@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.

@jkoritzinsky jkoritzinsky changed the title dev/jkoritzinsky/custom attribute constructors Move custom attribute materialization and invocation to managed code Sep 11, 2026
@jkoritzinsky
jkoritzinsky removed this pull request from stack #133661 September 11, 2026 03:11
@jkoritzinsky
jkoritzinsky added this pull request to stack #133663 September 11, 2026 03:11
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

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.

1 participant