Skip to content
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

Cache IsWindowsRuntimeType, which is expensive to read custom attributes #1005

Merged
merged 4 commits into from
Oct 4, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 71 additions & 65 deletions src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,33 +79,33 @@ public static IObjectReference GetObjectReferenceForInterface(IntPtr externalCom

// If we are free threaded, we do not need to keep track of context.
// This can either be if the object implements IAgileObject or the free threaded marshaler.
unsafe bool IsFreeThreaded()
{
if (unknownRef.TryAs<IUnknownVftbl>(typeof(ABI.WinRT.Interop.IAgileObject.Vftbl).GUID, out var agileRef) >= 0)
{
agileRef.Dispose();
return true;
}
else if (unknownRef.TryAs<ABI.WinRT.Interop.IMarshal.Vftbl>(out var marshalRef) >= 0)
{
try
{
Guid iid_IUnknown = typeof(IUnknownVftbl).GUID;
Guid iid_unmarshalClass;
var marshaler = new ABI.WinRT.Interop.IMarshal(marshalRef);
marshaler.GetUnmarshalClass(&iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass);
if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value)
{
return true;
}
}
finally
{
marshalRef.Dispose();
}
}
return false;
}
unsafe bool IsFreeThreaded()
{
if (unknownRef.TryAs<IUnknownVftbl>(typeof(ABI.WinRT.Interop.IAgileObject.Vftbl).GUID, out var agileRef) >= 0)
{
agileRef.Dispose();
return true;
}
else if (unknownRef.TryAs<ABI.WinRT.Interop.IMarshal.Vftbl>(out var marshalRef) >= 0)
{
try
{
Guid iid_IUnknown = typeof(IUnknownVftbl).GUID;
Guid iid_unmarshalClass;
var marshaler = new ABI.WinRT.Interop.IMarshal(marshalRef);
marshaler.GetUnmarshalClass(&iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass);
if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value)
{
return true;
}
}
finally
{
marshalRef.Dispose();
}
}
return false;
}
}

public static void RegisterProjectionAssembly(Assembly assembly) => TypeNameSupport.RegisterProjectionAssembly(assembly);
Expand Down Expand Up @@ -143,9 +143,9 @@ internal static List<ComInterfaceEntry> GetInterfaceTableEntries(Type type)
Vtable = (IntPtr)ifaceAbiType.GetAbiToProjectionVftblPtr()
});

if(!hasCustomIMarshalInterface && iid == typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID)
{
hasCustomIMarshalInterface = true;
if(!hasCustomIMarshalInterface && iid == typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID)
{
hasCustomIMarshalInterface = true;
}
}

Expand Down Expand Up @@ -213,25 +213,25 @@ internal static List<ComInterfaceEntry> GetInterfaceTableEntries(Type type)
{
IID = typeof(ABI.WinRT.Interop.IWeakReferenceSource.Vftbl).GUID,
Vtable = ABI.WinRT.Interop.IWeakReferenceSource.Vftbl.AbiToProjectionVftablePtr
});
// Add IMarhal implemented using the free threaded marshaler
// to all CCWs if it doesn't already have its own.
if (!hasCustomIMarshalInterface)
{
entries.Add(new ComInterfaceEntry
{
IID = typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID,
Vtable = ABI.WinRT.Interop.IMarshal.Vftbl.AbiToProjectionVftablePtr
});
});

// Add IMarhal implemented using the free threaded marshaler
// to all CCWs if it doesn't already have its own.
if (!hasCustomIMarshalInterface)
{
entries.Add(new ComInterfaceEntry
{
IID = typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID,
Vtable = ABI.WinRT.Interop.IMarshal.Vftbl.AbiToProjectionVftablePtr
});
}

// Add IAgileObject to all CCWs
entries.Add(new ComInterfaceEntry
{
IID = typeof(ABI.WinRT.Interop.IAgileObject.Vftbl).GUID,
Vtable = IUnknownVftbl.AbiToProjectionVftblPtr
});
});
return entries;
}

Expand Down Expand Up @@ -298,20 +298,20 @@ private static Func<IInspectable, object> CreateArrayFactory(Type implementation

return Expression.Lambda<Func<IInspectable, object>>(
Expression.Property(createInterfaceInstanceExpression, "Value"), parms).Compile();
}
// This is used to hold the reference to the native value type object (IReference) until the actual value in it (boxed as an object) gets cleaned up by GC
// This is done to avoid pointer reuse until GC cleans up the boxed object
private static ConditionalWeakTable<object, IInspectable> _boxedValueReferenceCache = new();
private static Func<IInspectable, object> CreateReferenceCachingFactory(Func<IInspectable, object> internalFactory)
{
return inspectable =>
{
object resultingObject = internalFactory(inspectable);
_boxedValueReferenceCache.Add(resultingObject, inspectable);
return resultingObject;
};
}

// This is used to hold the reference to the native value type object (IReference) until the actual value in it (boxed as an object) gets cleaned up by GC
// This is done to avoid pointer reuse until GC cleans up the boxed object
private static ConditionalWeakTable<object, IInspectable> _boxedValueReferenceCache = new();

private static Func<IInspectable, object> CreateReferenceCachingFactory(Func<IInspectable, object> internalFactory)
{
return inspectable =>
{
object resultingObject = internalFactory(inspectable);
_boxedValueReferenceCache.Add(resultingObject, inspectable);
return resultingObject;
};
}

internal static Func<IInspectable, object> CreateTypedRcwFactory(string runtimeClassName)
Expand Down Expand Up @@ -395,9 +395,10 @@ internal static string GetRuntimeClassForTypeCreation(IInspectable inspectable,
return runtimeClassName;
}

private static bool ShouldProvideIReference(Type type)
private readonly static ConcurrentDictionary<Type, bool> IsWindowsRuntimeTypeCache = new ConcurrentDictionary<Type, bool>();
Scottj1s marked this conversation as resolved.
Show resolved Hide resolved
private static bool IsWindowsRuntimeType(Type type)
Scottj1s marked this conversation as resolved.
Show resolved Hide resolved
{
static bool IsWindowsRuntimeType(Type type)
static bool IsWindowsRuntimeTypeHelper(Type type)
{
if ((type.GetCustomAttribute<WindowsRuntimeTypeAttribute>() is object) ||
Scottj1s marked this conversation as resolved.
Show resolved Hide resolved
WinRT.Projections.IsTypeWindowsRuntimeType(type))
Expand All @@ -412,15 +413,20 @@ static bool IsWindowsRuntimeType(Type type)
return false;
}

if (type == typeof(string) || type.IsTypeOfType())
return true;
if (type.IsDelegate())
return IsWindowsRuntimeType(type);
if (!type.IsValueType)
return false;
return type.IsPrimitive || IsWindowsRuntimeType(type);
return IsWindowsRuntimeTypeCache.GetOrAdd(type, (type) =>
{
if (type == typeof(string) || type.IsTypeOfType())
return true;
if (type.IsDelegate())
return IsWindowsRuntimeTypeHelper(type);
if (!type.IsValueType)
return false;
return type.IsPrimitive || IsWindowsRuntimeTypeHelper(type);
});
}

private static bool ShouldProvideIReference(Type type) => IsWindowsRuntimeType(type);

private static ComInterfaceEntry IPropertyValueEntry =>
new ComInterfaceEntry
{
Expand Down