-
Notifications
You must be signed in to change notification settings - Fork 31
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
ComPtr<T> improvements, new __uuidof<T> macro #151
Conversation
/// </summary> | ||
/// <param name="guid">The input <see cref="GUID"/> instance to read data for.</param> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static implicit operator Guid*(GUID guid) => guid.riid; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the codegen look like for this and the other implicit operator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say it looks quite nice 😄
Plus there's the fact that the tiered JIT could even elide the static constructor check entirely.
But other than this there's basically just the call to the static constructor (which we would've had anyway since Windows
has statically initialized fields as well), and then all the rest is completely elided by the JIT.
Guid* converter (click to expand):
public static unsafe Guid* GetAddr()
{
return __uuidof<ID3D12SomeType>();
}
sub rsp, 40
mov rcx, 0xD1FFAB1E
xor edx, edx
call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS
mov rax, 0xD1FFAB1E
mov rax, qword ptr [rax]
add rsp, 40
ret
Guid converter (click to expand):
public static unsafe Guid GetGuid()
{
return Windows.__uuidof<ID3D12Test>();
}
push rsi
sub rsp, 32
vzeroupper
mov rsi, rcx
mov rcx, 0xD1FFAB1E
xor edx, edx
call CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS
mov rax, 0xD1FFAB1E
mov rax, qword ptr [rax]
vmovdqu xmm0, xmmword ptr [rax]
vmovdqu xmmword ptr [rsi], xmm0
mov rax, rsi
add rsp, 32
pop rsi
ret
In particular for this as we have a direct comparison, the codegen is slightly smaller than just suing static GUIDs from the Windows
class, but of course this approach is still much easier to use and less error prone.
Accessing Windows.IID_Foo (click to expand):
public static unsafe Guid GetGuid()
{
return Windows.IID_Foo;
}
push rsi
sub rsp, 32
vzeroupper
mov rsi, rcx
mov rcx, 0xD1FFAB1E
mov edx, 5
call CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE
mov rax, 0xD1FFAB1E
mov rax, gword ptr [rax]
vmovdqu xmm0, xmmword ptr [rax+8]
vmovdqu xmmword ptr [rsi], xmm0
mov rax, rsi
add rsp, 32
pop rsi
ret
Considering that here we also have the prologue/epilogue that'd just go away once this method is just inlined 🚀
Co-authored-by: Tanner Gooding <tagoo@outlook.com>
/// <summary> | ||
/// A proxy type that wraps a pointer to GUID data. Values of this type can be implicitly | ||
/// converted to and assigned to <see cref="Guid"/>* or <see cref="Guid"/> parameters. | ||
/// </summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had only called out the doc comment syntax mismatch on the type, but it applies to all added doc comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right. Fixed in b358ae9 🙂
{ | ||
private readonly Guid* riid; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need AggressiveInlining
on these. They are extremely small and the JIT should handle it already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed in 65b7f00.
public ComPtr(T* other) | ||
{ | ||
ptr_ = other; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary newline was inserted here and a few other places in the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But they looked so nice 😛
Fixed in b2a4be6!
public readonly int As<U>(ref ComPtr<U> other) | ||
where U : unmanaged | ||
{ | ||
fixed (ComPtr<U>* p = &other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pin
could be avoided here by using a local and then internally assigning other.ptr_
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as below, removed in e10f572.
{ | ||
InternalAddRef(); | ||
|
||
fixed (ComPtr<T>* p = &other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pin could also be elided with the right helper. The address isn't actually being used in way that requires it to be fixed, so releasing the value and assigning the field directly is probably better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed all extra fixed blocks in e10f572 🚀
public void Dispose() | ||
{ | ||
InternalRelease(); | ||
T* pointer = ptr_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this changed from using InternalRelease()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we don't return the ref count so thought doing this manually and simplified could help the JIT with inlining?
private uint InternalRelease() | ||
{ | ||
uint @ref = 0; | ||
uint referenceCount = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The names here were matching the ones used in native code. It would be good to keep them where possible. Same for other places as well where changes have been made to the code.
The patterns and names were kept to help do visual validation and ease future ports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, that makes perfect sense 😄
Reverted those changes in 3f93d6e.
This PR includes a few tweaks and improvements to the
ComPtr<T>
type, and a port of the__uuidof<T>
macro.🆕 Added a port of the
__uuidof()
macro, as a new static__uuidof<T>()
API in theWindows
class. This makes it easy to grab aGuid*
value for a given typeT
, and similarly to the original macro it also can be used to assign aGuid
value directly to a local variable. This works through a specialUuidOfType
type that wraps aGuid*
pointer and adds implicit conversions when needed. This also indirectly speeds up a couple ofComPtr<T>
APIs as the reflection done intypeof(T).GUID
is no longer needed. Tier 1 JIT should also be able to completely replace the code with just a hardcoded address, but even without that it should be better thantypeof(T).GUID
every time. Also, this new API simplifies a lot having to grab arIID
value to use in various APIs.🆕 Also added some utility
As
andCopyTo
overloads.Diff for the API surface:
🚀 Improved codegen to
GetAddressOf
andReleaseAndGetAddressOf
. The code was previously using afixed
block, which resulted in poor codegen as the JIT isn't currently able to optimize that away. Fixed that usingUnsafe
APIs:📖 Minor code tweaks, added complete XML docs to the type