Skip to content

Optimize ConvertToUnmanaged codegen for sealed runtime classes#2345

Open
Sergio0694 wants to merge 6 commits intostaging/3.0from
dev/sergiopedri/optimize-sealed-class-ConvertToUnmanaged
Open

Optimize ConvertToUnmanaged codegen for sealed runtime classes#2345
Sergio0694 wants to merge 6 commits intostaging/3.0from
dev/sergiopedri/optimize-sealed-class-ConvertToUnmanaged

Conversation

@Sergio0694
Copy link
Member

This PR optimizes the ConvertToUnmanaged method generated by cswinrt.exe for sealed projected runtime classes.

Motivation

For sealed runtime classes, the RCW type is always unwrappable (since the type can never be subclassed). The current codegen unnecessarily goes through TryUnwrapObjectReference, which involves extra branching and an out parameter. We can skip this entirely and directly access NativeObjectReference on the value.

Changes

In write_class_marshaller (code_writers.h), the sealed branch now emits:

\\csharp
// Before (eg. FontWeightsMarshaller)
public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(FontWeights value)
{
if (WindowsRuntimeComWrappersMarshal.TryUnwrapObjectReference(value, out WindowsRuntimeObjectReference? objectReference))
{
return objectReference.AsValue();
}
return default;
}

// After
public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(FontWeights value)
{
return value?.NativeObjectReference.AsValue() ?? default;
}
\\

Non-sealed runtime classes are not affected by this change, as they may be subclassed and the RCW may not always be directly unwrappable.

For projected sealed runtime classes the RCW can never be subclassed, so unwraps are always valid. Replace the TryUnwrapObjectReference block with a direct access to value?.NativeObjectReference.AsValue() and add an explanatory comment in src/cswinrt/code_writers.h to simplify and optimize the logic.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link

Copilot AI left a comment

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 cswinrt.exe codegen to optimize the generated ConvertToUnmanaged implementation for sealed projected runtime classes, aiming to skip TryUnwrapObjectReference and directly use the underlying object reference.

Changes:

  • Update write_class_marshaller sealed-class branch to emit a direct NativeObjectReference access for ConvertToUnmanaged.
  • Add an explanatory comment describing why sealed runtime classes can skip unwrapping logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Sergio0694 Sergio0694 marked this pull request as draft March 18, 2026 07:43
Sergio0694 and others added 5 commits March 18, 2026 10:27
Address PR review feedback:
- Replace direct NativeObjectReference access (which is protected
  internal) with WindowsRuntimeObjectMarshaller.ConvertToUnmanaged,
  a public helper that takes the fast path for sealed types since
  HasUnwrappableNativeObjectReference is always true.
- Remove 'return default;' from the shared template and move it into
  each non-sealed branch, so the sealed branch's unconditional return
  no longer produces unreachable code (CS0162).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a new public method that directly unwraps the NativeObjectReference
from a WindowsRuntimeObject and returns it as a value, without
validating HasUnwrappableNativeObjectReference. This enables callers
that already know the object is unwrappable (e.g. sealed projected
runtime classes) to skip the TryUnwrapObjectReference overhead.

Also add class-level XML remarks documenting that no method in this
class performs input validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…degen

Update the sealed branch to emit a call to the new
UnwrapObjectReferenceUnsafe API, guarded by a null check. This avoids
both the TryUnwrapObjectReference overhead and the accessibility issue
with NativeObjectReference (which is protected internal).

Also restore the centralized 'return default;' in the template, since
all three branches now use the same conditional-return pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Have UnwrapObjectReferenceUnsafe return the raw object reference
directly, and let the generated caller do .AsValue() on it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Sergio0694 Sergio0694 marked this pull request as ready for review March 18, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants