Skip to content

Commit

Permalink
Reduce allocations for generated constructors (#1075)
Browse files Browse the repository at this point in the history
* net5+: remove Func<IObjectReference>

* lazy interfaces
  • Loading branch information
j0shuams authored Jan 19, 2022
1 parent e78db0e commit 3bf2eaa
Showing 1 changed file with 99 additions and 66 deletions.
165 changes: 99 additions & 66 deletions src/cswinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,14 @@ namespace cswinrt
}
}

void write_lazy_interface_type_name(writer& w, type_semantics const& ifaceTypeSemantics)
{
auto interfaceTypeCode = w.write_temp("%", bind<write_type_name>(ifaceTypeSemantics, typedef_name_type::Projected, true));
std::string interfaceTypeName = "_lazy_" + interfaceTypeCode;
std::regex re(R"-((\ |:|<|>|,|\.))-");
w.write("%", std::regex_replace(interfaceTypeName, re, "_"));
}

void write_lazy_interface_initialization(writer& w, TypeDef const& type)
{
int numLazyInterfaces = 0;
Expand All @@ -1247,37 +1255,39 @@ namespace cswinrt
}

numLazyInterfaces++;
auto lazy_interface_name = w.write_temp("%", bind<write_lazy_interface_type_name>(interface_type));
auto interface_name = write_type_name_temp(w, interface_type);
auto interface_abi_name = write_type_name_temp(w, interface_type, "%", typedef_name_type::ABI);

if (settings.netstandard_compat)
{
w.write(R"(
{typeof(%), new Lazy<%>(() => new %(GetReferenceForQI()))},)",
interface_name,
interface_abi_name,
interface_abi_name);
}
else
{
w.write(R"(
{typeof(%), new Lazy<%>(() => (%)(object)new SingleInterfaceOptimizedObject(typeof(%), _inner ?? ((IWinRTObject)this).NativeObject))},)",
interface_name,
interface_name,
auto interface_init_code = settings.netstandard_compat
? w.write_temp(R"(new %(GetReferenceForQI()))",
interface_abi_name)
: w.write_temp(R"((%)(object)new SingleInterfaceOptimizedObject(typeof(%), _inner ?? ((IWinRTObject)this).NativeObject))",
interface_name,
interface_name);
}

w.write(R"(
private volatile % %;
private % Make_%()
{
global::System.Threading.Interlocked.CompareExchange(ref %, %, null);
return %;
}
)",
interface_name,
lazy_interface_name,
interface_name,
lazy_interface_name,
lazy_interface_name,
interface_init_code,
lazy_interface_name);
});
}
});

if (numLazyInterfaces != 0)
{
w.write(R"(
_lazyInterfaces = new Dictionary<Type, object>(%)
{%
};
)", numLazyInterfaces, lazyInterfaces);
w.write(R"(%)", lazyInterfaces);
}
}

Expand Down Expand Up @@ -1876,7 +1886,9 @@ global::System.Collections.Concurrent.ConcurrentDictionary<RuntimeTypeHandle, ob
for (auto&& method : factory_type.MethodList())
{
method_signature signature{ method };
w.write(R"(
if (settings.netstandard_compat)
{
w.write(R"(
%public %(%) : this(((Func<%>)(() => {
IntPtr ptr = (%.%(%));
try
Expand All @@ -1889,18 +1901,59 @@ MarshalInspectable<object>.DisposeAbi(ptr);
}
}))())
{
)",
platform_attribute,
class_type.TypeName(),
bind_list<write_projection_parameter>(", ", signature.params()),
default_interface_name,
cache_object,
method.Name(),
bind_list<write_parameter_name_with_modifier>(", ", signature.params()),
"new " + default_interface_name
);
}
else
{
auto default_interface_typedef = for_typedef(w, get_type_semantics(get_default_interface(class_type)), [&](auto&& iface) { return iface; });
auto is_manually_gen_default_interface = is_manually_generated_iface(default_interface_typedef);

bool has_base_type = !std::holds_alternative<object_type>(get_type_semantics(class_type.Extends()));

w.write(R"(
%public %(%) %
{
IntPtr ptr = (%.%(%));
try
{
_inner = ComWrappersSupport.GetObjectReferenceForInterface(ptr);
%
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
)",
platform_attribute,
class_type.TypeName(),
bind_list<write_projection_parameter>(", ", signature.params()),
has_base_type ? ":base(global::WinRT.DerivedComposed.Instance)" : "",
cache_object,
method.Name(),
bind_list<write_parameter_name_with_modifier>(", ", signature.params()),
bind([&](writer& w)
{
if (is_manually_gen_default_interface)
{
auto projected_default_interface_name = get_default_interface_name(w, class_type, false);
w.write("_defaultLazy = new Lazy<%>(() => (%)new SingleInterfaceOptimizedObject(typeof(%), _inner));", projected_default_interface_name, projected_default_interface_name, projected_default_interface_name);
}
}));
}
w.write(R"(
ComWrappersSupport.RegisterObjectForInterface(this, ThisPtr);
%
}
)",
platform_attribute,
class_type.TypeName(),
bind_list<write_projection_parameter>(", ", signature.params()),
settings.netstandard_compat ? default_interface_name : "IObjectReference",
cache_object,
method.Name(),
bind_list<write_parameter_name_with_modifier>(", ", signature.params()),
settings.netstandard_compat ? "new " + default_interface_name : "",
settings.netstandard_compat ? "" : "ComWrappersHelper.Init(_inner, false);");
}
}
Expand Down Expand Up @@ -2060,8 +2113,6 @@ try
_inner = ComWrappersSupport.GetObjectReferenceForInterface(ptr);
var defaultInterface = new %(_inner);
_defaultLazy = new Lazy<%>(() => defaultInterface);
%
ComWrappersSupport.RegisterObjectForInterface(this, ThisPtr);
}
finally
Expand All @@ -2080,8 +2131,7 @@ MarshalInspectable<object>.DisposeAbi(ptr);
bind_list<write_parameter_name_with_modifier>(", ", params_without_objects),
[&](writer& w) {w.write("%", params_without_objects.empty() ? " " : ", "); },
default_interface_abi_name,
default_interface_abi_name,
bind<write_lazy_interface_initialization>(class_type));
default_interface_abi_name);
}
else
{
Expand All @@ -2097,7 +2147,6 @@ try
{
ComWrappersHelper.Init(isAggregation, this, composed, inner, out _inner);
%
%
}
finally
{
Expand All @@ -2121,8 +2170,7 @@ Marshal.Release(inner);
{
w.write("_defaultLazy = new Lazy<%>(() => (%)new SingleInterfaceOptimizedObject(typeof(%), _inner));", default_interface_name, default_interface_name, default_interface_name);
}
}),
bind<write_lazy_interface_initialization>(class_type));
}));
}
}
}
Expand Down Expand Up @@ -2856,25 +2904,15 @@ remove => %.ErrorsChanged -= value;
(is_default_interface ? "_default" : write_type_name_temp(w, interface_type, "AsInternal(new InterfaceTag<%>())"));
if (!is_default_interface && !wrapper_type)
{
if (settings.netstandard_compat)
{
w.write(R"(
private % AsInternal(InterfaceTag<%> _) => ((Lazy<%>)_lazyInterfaces[typeof(%)]).Value;
)",
interface_name,
interface_name,
interface_abi_name,
interface_name);
}
else if (is_manually_generated_iface(interface_type))
if (settings.netstandard_compat || is_manually_generated_iface(interface_type))
{
w.write(R"(
private % AsInternal(InterfaceTag<%> _) => ((Lazy<%>)_lazyInterfaces[typeof(%)]).Value;
private % AsInternal(InterfaceTag<%> _) => % ?? Make_%();
)",
interface_name,
interface_name,
interface_name,
interface_name);
bind<write_lazy_interface_type_name>(interface_type),
bind<write_lazy_interface_type_name>(interface_type));
}
}

Expand Down Expand Up @@ -6110,7 +6148,7 @@ public %IntPtr ThisPtr => _default.ThisPtr;
private IObjectReference _inner = null;
private readonly Lazy<%> _defaultLazy;
private readonly Dictionary<Type, object> _lazyInterfaces;
%
private % _default => _defaultLazy.Value;
%
Expand All @@ -6123,7 +6161,6 @@ return MarshalInspectable<%>.FromAbi(thisPtr);
% %(% ifc)%
{
_defaultLazy = new Lazy<%>(() => ifc);
%
%}
%
Expand All @@ -6149,6 +6186,7 @@ private % AsInternal(InterfaceTag<%> _) => _default;
type_name,
derived_new,
default_interface_abi_name,
bind<write_lazy_interface_initialization>(type),
default_interface_abi_name,
bind<write_attributed_types>(type),
derived_new,
Expand All @@ -6159,7 +6197,7 @@ private % AsInternal(InterfaceTag<%> _) => _default;
default_interface_abi_name,
bind<write_base_constructor_dispatch_netstandard>(base_semantics),
default_interface_abi_name,
bind<write_lazy_interface_initialization>(type),

[&](writer& w)
{
if (!gc_pressure_amount) return;
Expand Down Expand Up @@ -6192,13 +6230,11 @@ GC.RemoveMemoryPressure(%);
protected %(global::WinRT.DerivedComposed _)%
{
_defaultLazy = new Lazy<%>(() => GetDefaultReference<%.Vftbl>());
%
})",
type.TypeName(),
has_base_type ? ":base(_)" : "",
default_interface_abi_name,
default_interface_abi_name,
bind<write_lazy_interface_initialization>(type));
default_interface_abi_name);
}

std::string_view access_spec = "protected ";
Expand Down Expand Up @@ -6260,7 +6296,7 @@ private IntPtr ThisPtr => _inner == null ? (((IWinRTObject)this).NativeObject).T
private IObjectReference _inner = null;
%
private readonly Dictionary<Type, object> _lazyInterfaces;
%
%
%
Expand All @@ -6275,7 +6311,6 @@ return MarshalInspectable<%>.FromAbi(thisPtr);
{
_inner = objRef.As(GuidGenerator.GetIID(typeof(%).GetHelperType()));
%
%
}
public static bool operator ==(% x, % y) => (x?.ThisPtr ?? IntPtr.Zero) == (y?.ThisPtr ?? IntPtr.Zero);
Expand All @@ -6297,6 +6332,7 @@ private struct InterfaceTag<I>{};
type_name,
bind<write_type_inheritance>(type, base_semantics, true, false),
type_name,
bind<write_lazy_interface_initialization>(type),
bind([&](writer& w)
{
if (is_manually_gen_default_interface)
Expand Down Expand Up @@ -6326,7 +6362,6 @@ private struct InterfaceTag<I>{};
w.write("_defaultLazy = new Lazy<%>(() => (%)new SingleInterfaceOptimizedObject(typeof(%), _inner));", default_interface_name, default_interface_name, default_interface_name);
}
}),
bind<write_lazy_interface_initialization>(type),
// Equality operators
type_name,
type_name,
Expand All @@ -6343,18 +6378,16 @@ private struct InterfaceTag<I>{};
protected %(global::WinRT.DerivedComposed _)%
{
%
%
})",
type.TypeName(),
has_base_type ? ":base(_)" : "",
bind([&](writer& w)
{
if (is_manually_gen_default_interface)
{
if (is_manually_gen_default_interface)
{
w.write("_defaultLazy = new Lazy<%>(() => (%)new IInspectable(((IWinRTObject)this).NativeObject));", default_interface_name, default_interface_name);
}
}),
bind<write_lazy_interface_initialization>(type));
w.write("_defaultLazy = new Lazy<%>(() => (%)new IInspectable(((IWinRTObject)this).NativeObject));", default_interface_name, default_interface_name);
}
}));
w.write(R"(
bool IWinRTObject.HasUnwrappableNativeObject => this.GetType() == typeof(%);)",
type.TypeName());
Expand Down

0 comments on commit 3bf2eaa

Please sign in to comment.