From 8d849c1045e71cbfc6c361effa913eda98204eb3 Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 11 Jul 2019 16:23:43 -0700 Subject: [PATCH] Optimize C++/WinRT implementation signatures (#512) --- src/tool/cppwinrt/cppwinrt/code_writers.h | 15 +-- .../cppwinrt/cppwinrt/component_writers.h | 10 +- src/tool/cppwinrt/cppwinrt/helpers.h | 109 ++++++++++-------- 3 files changed, 74 insertions(+), 60 deletions(-) diff --git a/src/tool/cppwinrt/cppwinrt/code_writers.h b/src/tool/cppwinrt/cppwinrt/code_writers.h index 749f0e9c..d35c46a2 100644 --- a/src/tool/cppwinrt/cppwinrt/code_writers.h +++ b/src/tool/cppwinrt/cppwinrt/code_writers.h @@ -899,7 +899,8 @@ namespace xlang auto param_type = std::get_if(¶m_signature->Type().Type()); - if (w.async_types || (param_type && *param_type != ElementType::String && *param_type != ElementType::Object)) + if ((!is_put_overload(method_signature.method()) && w.async_types) || + (param_type && *param_type != ElementType::String && *param_type != ElementType::Object)) { w.write("%", param_signature->Type()); } @@ -924,7 +925,7 @@ namespace xlang static void write_consume_declaration(writer& w, MethodDef const& method) { method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); auto method_name = get_name(method); auto type = method.Parent(); @@ -1060,7 +1061,7 @@ namespace xlang { auto method_name = get_name(method); method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); std::string_view format; @@ -1120,7 +1121,7 @@ namespace xlang { auto method_name = get_name(method); method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); // // Note: this use of a lambda is a workaround for a Visual C++ compiler bug: @@ -1737,7 +1738,7 @@ namespace xlang } method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); std::string upcall = "this->shim()."; upcall += get_name(method); @@ -2805,7 +2806,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable { method_signature signature{ method }; auto method_name = get_name(method); - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); if (settings.component_opt && settings.component_filter.includes(type)) { @@ -2845,7 +2846,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable { method_signature signature{ method }; auto method_name = get_name(method); - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); { auto format = R"( inline auto %::%(%) diff --git a/src/tool/cppwinrt/cppwinrt/component_writers.h b/src/tool/cppwinrt/cppwinrt/component_writers.h index 2c05bcfd..8ab80f73 100644 --- a/src/tool/cppwinrt/cppwinrt/component_writers.h +++ b/src/tool/cppwinrt/cppwinrt/component_writers.h @@ -474,7 +474,7 @@ catch (...) { return winrt::to_hresult(); } { method_signature signature{ method }; auto method_name = get_name(method); - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); if (is_add_overload(method) || is_remove_overload(method)) { @@ -950,7 +950,7 @@ namespace winrt::@::implementation for (auto&& method : factory.type.MethodList()) { method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); auto method_name = get_name(method); w.write(" static % %(%)%;\n", @@ -974,7 +974,7 @@ namespace winrt::@::implementation for (auto&& method : info.type.MethodList()) { method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); auto method_name = get_name(method); w.write(" % %(%)%;\n", @@ -1105,7 +1105,7 @@ namespace winrt::@::implementation for (auto&& method : factory.type.MethodList()) { method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); auto method_name = get_name(method); w.write(format, @@ -1136,7 +1136,7 @@ namespace winrt::@::implementation )"; method_signature signature{ method }; - w.async_types = is_async(method, signature); + w.async_types = signature.is_async(); auto method_name = get_name(method); w.write(format, diff --git a/src/tool/cppwinrt/cppwinrt/helpers.h b/src/tool/cppwinrt/cppwinrt/helpers.h index 2c94aec4..05c3df0b 100644 --- a/src/tool/cppwinrt/cppwinrt/helpers.h +++ b/src/tool/cppwinrt/cppwinrt/helpers.h @@ -12,22 +12,28 @@ namespace xlang return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count(); } + static bool is_put_overload(MethodDef const& method) + { + return method.SpecialName() && starts_with(method.Name(), "put_"); + } + struct method_signature { explicit method_signature(MethodDef const& method) : - m_method(method.Signature()) + m_method(method), + m_signature(method.Signature()) { auto params = method.ParamList(); - if (m_method.ReturnType() && params.first != params.second && params.first.Sequence() == 0) + if (m_signature.ReturnType() && params.first != params.second && params.first.Sequence() == 0) { m_return = params.first; ++params.first; } - for (uint32_t i{}; i != size(m_method.Params()); ++i) + for (uint32_t i{}; i != size(m_signature.Params()); ++i) { - m_params.emplace_back(params.first + i, &m_method.Params().first[i]); + m_params.emplace_back(params.first + i, &m_signature.Params().first[i]); } } @@ -43,7 +49,7 @@ namespace xlang auto const& return_signature() const { - return m_method.ReturnType(); + return m_signature.ReturnType(); } auto return_param_name() const @@ -62,9 +68,58 @@ namespace xlang return name; } + MethodDef const& method() const + { + return m_method; + } + + bool is_async() const + { + // WinRT parameter passing conventions include the notion that input parameters of collection types may be read + // or copied but should not be stored directly since this would lead to instability as the collection is shared + // by the caller and callee. The exception to this rule is property setters where the callee may simply store a + // reference to the collection. The collection thus becomes async in the sense that it is expected to remain + // valid beyond the duration of the call. + + if (is_put_overload(m_method)) + { + return true; + } + + if (!m_signature.ReturnType()) + { + return false; + } + + bool async{}; + + call(m_signature.ReturnType().Type().Type(), + [&](coded_index const& type) + { + auto const& [type_namespace, type_name] = get_type_namespace_and_name(type); + async = type_namespace == "Windows.Foundation" && type_name == "IAsyncAction"; + }, + [&](GenericTypeInstSig const& type) + { + auto const& [type_namespace, type_name] = get_type_namespace_and_name(type.GenericType()); + + if (type_namespace == "Windows.Foundation") + { + async = + type_name == "IAsyncOperation`1" || + type_name == "IAsyncActionWithProgress`1" || + type_name == "IAsyncOperationWithProgress`2"; + } + }, + [](auto&&) {}); + + return async; + } + private: - MethodDefSig m_method; + MethodDef m_method; + MethodDefSig m_signature; std::vector> m_params; Param m_return; }; @@ -133,11 +188,6 @@ namespace xlang return method.SpecialName() && starts_with(method.Name(), "add_"); } - static bool is_put_overload(MethodDef const& method) - { - return method.SpecialName() && starts_with(method.Name(), "put_"); - } - static bool is_get_overload(MethodDef const& method) { return method.SpecialName() && starts_with(method.Name(), "get_"); @@ -204,43 +254,6 @@ namespace xlang return {}; } - static bool is_async(MethodDef const& method, method_signature const& method_signature) - { - if (is_put_overload(method)) - { - return true; - } - - if (!method_signature.return_signature()) - { - return false; - } - - bool async{}; - - call(method_signature.return_signature().Type().Type(), - [&](coded_index const& type) - { - auto const& [type_namespace, type_name] = get_type_namespace_and_name(type); - async = type_namespace == "Windows.Foundation" && type_name == "IAsyncAction"; - }, - [&](GenericTypeInstSig const& type) - { - auto const& [type_namespace, type_name] = get_type_namespace_and_name(type.GenericType()); - - if (type_namespace == "Windows.Foundation") - { - async = - type_name == "IAsyncOperation`1" || - type_name == "IAsyncActionWithProgress`1" || - type_name == "IAsyncOperationWithProgress`2"; - } - }, - [](auto&&) {}); - - return async; - } - static TypeDef get_base_class(TypeDef const& derived) { auto extends = derived.Extends();