-
Notifications
You must be signed in to change notification settings - Fork 199
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
Add RCW support #992
Add RCW support #992
Conversation
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
Add some basic tests? |
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
@jkotas I am definitely ready for you to review this. |
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
This shold say RCW. I had it swapped in the tracking issue - I have fixed it there. |
Thanks. It was a big linguistic battle inside me. Since I have a lot of other question, in order to not too much distract you, I decide that I do not understand some language tricks. |
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
|
||
~NativeObjectWrapper() | ||
{ | ||
_comWrappers._rcwCache.Remove(_externalComObject); |
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.
Does this need to take the lock?
@@ -317,7 +349,7 @@ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, Create | |||
/// <remarks> | |||
/// If <paramref name="impl" /> is <c>null</c>, the global instance (if registered) will be used. | |||
/// </remarks> | |||
private static bool TryGetOrCreateObjectForComInstanceInternal( | |||
private static unsafe bool TryGetOrCreateObjectForComInstanceInternal( | |||
ComWrappers impl, |
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.
Can this be an instance method instead? I do not see the point of passing in impl explicitly. (CreateCCW has the same issue.)
{ | ||
if (impl._rcwCache.TryGetValue(externalComObject, out var existingHandle)) | ||
{ | ||
if (existingHandle.IsAllocated) |
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.
IsAllocated should be always true here. We should not ever get unallocated GCHandle from the Dictionary.
} | ||
else | ||
{ | ||
GCHandle proxyHandle = GCHandle.Alloc(retValue, GCHandleType.Weak); |
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.
For symetry, it would be nice to allocated the GCHandle and add it to the table in NativeObjectWrapper constructor - since the opposite is done in the NativeObjectWrapper finalizer.
@jkotas I think I address your feedback. |
public delegate* unmanaged<IntPtr, uint> Release; | ||
private IntPtr _externalComObject; | ||
private ComWrappers _comWrappers; | ||
public GCHandle ProxyHandle; |
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 would keep it as _proxyHandle
. (Some of the places in the file are actually still refering to the field as _proxyHandle
.)
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.
Done.
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
~NativeObjectWrapper() | ||
{ | ||
_comWrappers.RemoveRCWFromCache(_externalComObject); | ||
_proxyHandle.Free(); |
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 can be unallocated handle if GCHandle.Alloc in the constructor fails. This should get the IsAllocated check.
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.
Done
…e/InteropServices/ComWrappers.CoreRT.cs Co-authored-by: Jan Kotas <[email protected]>
@jkotas I think I address your feedback again |
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Show resolved
Hide resolved
…e/InteropServices/ComWrappers.CoreRT.cs Co-authored-by: Jan Kotas <[email protected]>
...lr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
Outdated
Show resolved
Hide resolved
…e/InteropServices/ComWrappers.CoreRT.cs
|
||
StoreManagedValue(codeStream); | ||
|
||
codeStream.EmitLabel(lNull); |
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.
Is it correct to skip storing the managed value for null?
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 think yes. At least this pattern is everywhere.
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.
Managed value initialized as null
by runtime guarantee, so load/store usually going in pairs. Then somebody do actual return. At least this is how I understand this.
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.
Managed value initialized as null by runtime guarantee,
Where is it guaranteed?
I went through all TransformNativeToManaged methods and all of them end with Store. I have not found one that skips the store.
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.
LayoutClassPtrMarshaller, AsAnyMarshaller for example
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 managed value for these marshallers is a pointer to the structure that they are marshalling. It is not the case here.
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 I was trying to say that
.method public hidebysig specialname
instance int32 get_Set() cil managed
{
.maxstack 1
.locals init (int32 V_0)
IL_0009: ldloc.0
IL_000a: ret
} // end of method SetProperty::get_Set
is equivalent for
int Set => 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.
I miss your previous message. Will have to check what kind of IL actually generated to validate that what I'm saying is correct.
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.
You may be right, but I would still simplify this to a simple ConvertNativeComInterfaceToManaged. If the store is redudandant, the JIT will eliminate it after inlining ConvertNativeComInterfaceToManaged.
LGTM otherwise. Thank you! |
See #306