summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Cavalcante de Sousa <lucas@expertisesolutions.com.br>2020-02-28 15:58:08 +0000
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2020-03-23 14:18:16 -0300
commit117450e3fac0be15c9cb292cb158d9398b6f30ef (patch)
treef22fc424f0e4e09151744057991c6a683f94dbce
parente5cec5dacca53017d1fb260181993f2a81264577 (diff)
C#: Update C# code-generation to use a new ICustomMarshaler in some string usages that were leaking
When `C` calls a function that return/has an out string and it was overwritten by `C#` inherit class the `C` portion wasn't cleaning its copy. Now, when a `C` calls a `C#` delegate function, `Strings` that are `out` values or `return` values use a new marshaler (specific to this case) that uses Eina short lived strings (`Eina_Slstr`) instead of duplicating it with `strdup`, so at some point, the string passed to `C` is deleted. To do so, a `direction_context` (a new `Context` at `generation_contexts.hh`) was created. It is only used when a C# delegate is being called from C (so this context is only set in `function_definition.hh` and `property_definition.hh`, where it is set to `native_to_manage` to indicate that it is a native call to a managed function). When this `direction_context` is set and the `String` being marshaled is not marked with an `@move` tag and it is an `out` or `return` value, the new `StringOutMarshaler` (implemented at `iwrapper.cs`) is used (instead of `StringKeepOwnershipMarshaler`). When marshaling a managed data to native this marshaler uses eina short lived string (`Eina_Slstr`) that will be automatically deleted. This delete is bounded to "the loop of the current thread or until the clear function is called explicitly" as said at `src/lib/eina/eina_slstr.h`. Reviewed-by: Felipe Magno de Almeida <felipe@expertisesolutions.com.br> Differential Revision: https://phab.enlightenment.org/D11434
-rw-r--r--src/bin/eolian_mono/eolian/mono/function_definition.hh24
-rw-r--r--src/bin/eolian_mono/eolian/mono/generation_contexts.hh13
-rw-r--r--src/bin/eolian_mono/eolian/mono/marshall_annotation.hh21
-rw-r--r--src/bin/eolian_mono/eolian/mono/property_definition.hh26
-rw-r--r--src/bindings/mono/eina_mono/eina_common.cs8
-rw-r--r--src/bindings/mono/eo_mono/iwrapper.cs39
6 files changed, 106 insertions, 25 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/function_definition.hh b/src/bin/eolian_mono/eolian/mono/function_definition.hh
index 5fc0e84fbf..975335f4eb 100644
--- a/src/bin/eolian_mono/eolian/mono/function_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/function_definition.hh
@@ -47,7 +47,7 @@ struct native_function_definition_generator
47{ 47{
48 attributes::klass_def const* klass; 48 attributes::klass_def const* klass;
49 std::vector<attributes::property_def> properties; 49 std::vector<attributes::property_def> properties;
50 50
51 template <typename OutputIterator, typename Context> 51 template <typename OutputIterator, typename Context>
52 bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const 52 bool generate(OutputIterator sink, attributes::function_def const& f, Context const& context) const
53 { 53 {
@@ -72,7 +72,7 @@ struct native_function_definition_generator
72 if (property_generate_wrapper_setter (*it, context)) 72 if (property_generate_wrapper_setter (*it, context))
73 return true; 73 return true;
74 } 74 }
75 75
76 auto const& indent = current_indentation(context); 76 auto const& indent = current_indentation(context);
77 77
78 // Delegate for the C# method we will export to EO as a method implementation. 78 // Delegate for the C# method we will export to EO as a method implementation.
@@ -90,7 +90,9 @@ struct native_function_definition_generator
90 (marshall_annotation << " " << marshall_parameter) 90 (marshall_annotation << " " << marshall_parameter)
91 ) % ", ") 91 ) % ", ")
92 << ");\n\n") 92 << ");\n\n")
93 .generate(sink, std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters), context)) 93 .generate(sink,
94 std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters),
95 context_add_tag(direction_context{direction_context::native_to_managed}, context)))
94 return false; 96 return false;
95 97
96 // API delegate is the wrapper for the Eo methods exported from C that we will use from C#. 98 // API delegate is the wrapper for the Eo methods exported from C that we will use from C#.
@@ -186,7 +188,7 @@ struct native_function_definition_generator
186 , f.c_name 188 , f.c_name
187 , f.parameters 189 , f.parameters
188 ) 190 )
189 , context)) 191 , context_add_tag(direction_context{direction_context::native_to_managed}, context)))
190 return false; 192 return false;
191 193
192 // Static functions do not need to be called from C 194 // Static functions do not need to be called from C
@@ -196,13 +198,15 @@ struct native_function_definition_generator
196 // This is the delegate that will be passed to Eo to be called from C. 198 // This is the delegate that will be passed to Eo to be called from C.
197 if(!as_generator( 199 if(!as_generator(
198 indent << "private static " << f.c_name << "_delegate " << f.c_name << "_static_delegate;\n\n" 200 indent << "private static " << f.c_name << "_delegate " << f.c_name << "_static_delegate;\n\n"
199 ).generate(sink, attributes::unused, context)) 201 ).generate(sink,
202 attributes::unused,
203 context_add_tag(direction_context{direction_context::native_to_managed}, context)))
200 return false; 204 return false;
201 205
202 return true; 206 return true;
203 } 207 }
204}; 208};
205 209
206struct function_definition_generator 210struct function_definition_generator
207{ 211{
208 template <typename OutputIterator, typename Context> 212 template <typename OutputIterator, typename Context>
@@ -232,7 +236,7 @@ struct function_definition_generator
232 if (property_generate_wrapper_setter (*it, context)) 236 if (property_generate_wrapper_setter (*it, context))
233 function_scope = "internal "; 237 function_scope = "internal ";
234 } 238 }
235 239
236 // Do not generate static function for concrete class 240 // Do not generate static function for concrete class
237 if (is_concrete && f.is_static) 241 if (is_concrete && f.is_static)
238 return true; 242 return true;
@@ -402,7 +406,7 @@ struct property_wrapper_definition_generator
402 return true; 406 return true;
403 if (property.setter && !property.setter->keys.empty()) 407 if (property.setter && !property.setter->keys.empty())
404 return true; 408 return true;
405 409
406 if (property.getter && property.setter) 410 if (property.getter && property.setter)
407 { 411 {
408 if (property.setter->values.size() != property.getter->values.size()) 412 if (property.setter->values.size() != property.getter->values.size())
@@ -498,7 +502,7 @@ struct property_wrapper_definition_generator
498 502
499 if (property.setter && property.setter->explicit_return_type.c_type == "Eina_Success_Flag") 503 if (property.setter && property.setter->explicit_return_type.c_type == "Eina_Success_Flag")
500 set_has_return_error = true; 504 set_has_return_error = true;
501 505
502 if (parameters.size() == 1) 506 if (parameters.size() == 1)
503 { 507 {
504 if (!as_generator( 508 if (!as_generator(
@@ -674,7 +678,7 @@ struct attributes_needed< ::eolian_mono::property_wrapper_definition_generator>
674template <> 678template <>
675struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant<int, 1> {}; 679struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant<int, 1> {};
676} 680}
677 681
678} } } 682} } }
679 683
680#endif 684#endif
diff --git a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
index f7376f056a..6cbdb19a36 100644
--- a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
+++ b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh
@@ -50,6 +50,19 @@ struct class_context
50 {} 50 {}
51}; 51};
52 52
53struct direction_context
54{
55 enum direction {
56 native_to_managed,
57 managed_to_native,
58 };
59 direction current_direction;
60
61 direction_context(direction current_direction)
62 : current_direction(current_direction)
63 {}
64};
65
53struct indentation_context 66struct indentation_context
54{ 67{
55 constexpr indentation_context(indentation_context const& other) = default; 68 constexpr indentation_context(indentation_context const& other) = default;
diff --git a/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh b/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh
index a9fc45d7da..527771959f 100644
--- a/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh
+++ b/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh
@@ -28,8 +28,9 @@ namespace eolian_mono {
28namespace eina = efl::eina; 28namespace eina = efl::eina;
29 29
30namespace detail { 30namespace detail {
31 31
32template <typename OutputIterator, typename Context> 32template <typename OutputIterator, typename Context>
33
33struct marshall_annotation_visitor_generate 34struct marshall_annotation_visitor_generate
34{ 35{
35 mutable OutputIterator sink; 36 mutable OutputIterator sink;
@@ -41,7 +42,7 @@ struct marshall_annotation_visitor_generate
41 42
42 typedef marshall_type_visitor_generate<OutputIterator, Context> visitor_type; 43 typedef marshall_type_visitor_generate<OutputIterator, Context> visitor_type;
43 typedef bool result_type; 44 typedef bool result_type;
44 45
45 bool operator()(attributes::regular_type_def const& regular) const 46 bool operator()(attributes::regular_type_def const& regular) const
46 { 47 {
47 using attributes::regular_type_def; 48 using attributes::regular_type_def;
@@ -60,7 +61,13 @@ struct marshall_annotation_visitor_generate
60 {"string", true, [] { 61 {"string", true, [] {
61 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))"; 62 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))";
62 }}, 63 }},
63 {"string", false, [] { 64 {"string", false, [this] {
65 auto is_native_to_managed = false;
66 if constexpr (efl::eolian::grammar::tag_check<direction_context, Context>::value)
67 is_native_to_managed = context_find_tag<direction_context>(*context).current_direction == direction_context::native_to_managed;
68
69 if((is_out || is_return) && is_native_to_managed)
70 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutMarshaler))";
64 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))"; 71 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))";
65 }}, 72 }},
66 {"mstring", true, [] { 73 {"mstring", true, [] {
@@ -98,7 +105,13 @@ struct marshall_annotation_visitor_generate
98 {"string", true, [] { 105 {"string", true, [] {
99 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))"; 106 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))";
100 }}, 107 }},
101 {"string", false, [] { 108 {"string", false, [this] {
109 auto is_native_to_managed = false;
110 if constexpr (efl::eolian::grammar::tag_check<direction_context, Context>::value)
111 is_native_to_managed = context_find_tag<direction_context>(*context).current_direction == direction_context::native_to_managed;
112
113 if((is_out || is_return) && is_native_to_managed)
114 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutMarshaler))";
102 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))"; 115 return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))";
103 }}, 116 }},
104 {"mstring", true, [] { 117 {"mstring", true, [] {
diff --git a/src/bin/eolian_mono/eolian/mono/property_definition.hh b/src/bin/eolian_mono/eolian/mono/property_definition.hh
index 703b70269d..827454fd10 100644
--- a/src/bin/eolian_mono/eolian/mono/property_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/property_definition.hh
@@ -37,7 +37,7 @@ struct compare_get_and_set_value_type
37 inline bool operator () (attributes::parameter_def const& get, attributes::parameter_def const& set) const; 37 inline bool operator () (attributes::parameter_def const& get, attributes::parameter_def const& set) const;
38 inline bool operator () (attributes::type_def const& get, attributes::type_def const& set) const; 38 inline bool operator () (attributes::type_def const& get, attributes::type_def const& set) const;
39}; 39};
40 40
41struct compare_get_and_set_value_type_overload 41struct compare_get_and_set_value_type_overload
42{ 42{
43 template <typename T, typename U> 43 template <typename T, typename U>
@@ -64,7 +64,7 @@ struct compare_get_and_set_value_type_overload
64 64
65 typedef bool result_type; 65 typedef bool result_type;
66}; 66};
67 67
68inline bool compare_get_and_set_value_type::operator () (attributes::parameter_def const& get, attributes::parameter_def const& set) const 68inline bool compare_get_and_set_value_type::operator () (attributes::parameter_def const& get, attributes::parameter_def const& set) const
69{ 69{
70 return efl::eina::visit(compare_get_and_set_value_type_overload{}, get.type.original_type, set.type.original_type); 70 return efl::eina::visit(compare_get_and_set_value_type_overload{}, get.type.original_type, set.type.original_type);
@@ -73,7 +73,7 @@ inline bool compare_get_and_set_value_type::operator () (attributes::type_def co
73{ 73{
74 return efl::eina::visit(compare_get_and_set_value_type_overload{}, get.original_type, set.original_type); 74 return efl::eina::visit(compare_get_and_set_value_type_overload{}, get.original_type, set.original_type);
75} 75}
76 76
77template <typename Context> 77template <typename Context>
78bool property_generate_wrapper_both_check(attributes::property_def const& property, Context const& context) 78bool property_generate_wrapper_both_check(attributes::property_def const& property, Context const& context)
79{ 79{
@@ -87,7 +87,7 @@ bool property_generate_wrapper_both_check(attributes::property_def const& proper
87 87
88 if ((is_concrete || is_interface) && is_static) 88 if ((is_concrete || is_interface) && is_static)
89 return false; 89 return false;
90 90
91 if (!property.getter) 91 if (!property.getter)
92 return false; 92 return false;
93 93
@@ -102,7 +102,7 @@ bool property_generate_wrapper_both_check(attributes::property_def const& proper
102 else 102 else
103 return false; 103 return false;
104 } 104 }
105 105
106 return true; 106 return true;
107} 107}
108 108
@@ -144,7 +144,7 @@ bool property_generate_wrapper_setter (attributes::property_def const& property,
144 144
145 if (property.setter->explicit_return_type != attributes::void_) 145 if (property.setter->explicit_return_type != attributes::void_)
146 return false; 146 return false;
147 147
148 if (!property.setter->keys.empty()) 148 if (!property.setter->keys.empty())
149 return false; 149 return false;
150 150
@@ -192,7 +192,9 @@ struct native_property_function_definition_generator
192 (marshall_annotation << " " << marshall_parameter) 192 (marshall_annotation << " " << marshall_parameter)
193 ) % ", ") 193 ) % ", ")
194 << ");\n\n") 194 << ");\n\n")
195 .generate(sink, std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters), context)) 195 .generate(sink,
196 std::make_tuple(f.return_type, f.return_type, f.c_name, f.parameters),
197 context_add_tag(direction_context{direction_context::native_to_managed}, context)))
196 return false; 198 return false;
197 199
198 // API delegate is the wrapper for the Eo methods exported from C that we will use from C#. 200 // API delegate is the wrapper for the Eo methods exported from C that we will use from C#.
@@ -279,7 +281,7 @@ struct native_property_function_definition_generator
279 281
280 if(!f.keys.empty() && !as_generator(lit("[(") << (native_argument_invocation % ", ") << ")]").generate (sink, f.keys, context)) 282 if(!f.keys.empty() && !as_generator(lit("[(") << (native_argument_invocation % ", ") << ")]").generate (sink, f.keys, context))
281 return false; 283 return false;
282 284
283 if(!as_generator 285 if(!as_generator
284 (" = (" 286 (" = ("
285 << (native_tuple_argument_invocation % ", ") << ");\n" 287 << (native_tuple_argument_invocation % ", ") << ");\n"
@@ -340,7 +342,9 @@ struct native_property_function_definition_generator
340 // This is the delegate that will be passed to Eo to be called from C. 342 // This is the delegate that will be passed to Eo to be called from C.
341 if(!as_generator( 343 if(!as_generator(
342 indent << "private static " << f.c_name << "_delegate " << f.c_name << "_static_delegate;\n\n" 344 indent << "private static " << f.c_name << "_delegate " << f.c_name << "_static_delegate;\n\n"
343 ).generate(sink, attributes::unused, context)) 345 ).generate(sink,
346 attributes::unused,
347 context_add_tag(direction_context{direction_context::native_to_managed}, context)))
344 return false; 348 return false;
345 return true; 349 return true;
346 }; 350 };
@@ -377,10 +381,10 @@ template <>
377struct is_generator< ::eolian_mono::native_property_function_definition_generator> : std::true_type {}; 381struct is_generator< ::eolian_mono::native_property_function_definition_generator> : std::true_type {};
378 382
379namespace type_traits { 383namespace type_traits {
380 384
381template <> 385template <>
382struct attributes_needed< ::eolian_mono::native_property_function_definition_generator> : std::integral_constant<int, 1> {}; 386struct attributes_needed< ::eolian_mono::native_property_function_definition_generator> : std::integral_constant<int, 1> {};
383 387
384} } } } 388} } } }
385 389
386#endif 390#endif
diff --git a/src/bindings/mono/eina_mono/eina_common.cs b/src/bindings/mono/eina_mono/eina_common.cs
index a4f2ff4c5f..014e77d020 100644
--- a/src/bindings/mono/eina_mono/eina_common.cs
+++ b/src/bindings/mono/eina_mono/eina_common.cs
@@ -55,6 +55,9 @@ internal static partial class NativeCustomExportFunctions
55 efl_mono_native_free_addr_get(); 55 efl_mono_native_free_addr_get();
56 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr 56 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr
57 efl_mono_native_efl_unref_addr_get(); 57 efl_mono_native_efl_unref_addr_get();
58
59 [DllImport(efl.Libs.Eina)] public static extern IntPtr
60 eina_slstr_copy_new(string str);
58} 61}
59 62
60/// <summary>Wrapper around native memory DllImport'd functions. 63/// <summary>Wrapper around native memory DllImport'd functions.
@@ -94,6 +97,11 @@ public static class MemoryNative
94 return NativeCustomExportFunctions.efl_mono_native_strdup(str); 97 return NativeCustomExportFunctions.efl_mono_native_strdup(str);
95 } 98 }
96 99
100 public static IntPtr SlstrCopyNew(string str)
101 {
102 return NativeCustomExportFunctions.eina_slstr_copy_new(str);
103 }
104
97 /// <summary> 105 /// <summary>
98 /// Retrieves an instance of a string for use in program. 106 /// Retrieves an instance of a string for use in program.
99 /// <para>Since EFL 1.23.</para> 107 /// <para>Since EFL 1.23.</para>
diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs
index ceae250bc9..626777f7d5 100644
--- a/src/bindings/mono/eo_mono/iwrapper.cs
+++ b/src/bindings/mono/eo_mono/iwrapper.cs
@@ -1508,6 +1508,45 @@ class StringPassOwnershipMarshaler : ICustomMarshaler
1508 static private StringPassOwnershipMarshaler marshaler; 1508 static private StringPassOwnershipMarshaler marshaler;
1509} 1509}
1510 1510
1511
1512class StringOutMarshaler: ICustomMarshaler
1513{
1514 public object MarshalNativeToManaged(IntPtr pNativeData)
1515 {
1516 return Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
1517 }
1518
1519 public IntPtr MarshalManagedToNative(object managedObj)
1520 {
1521 return Eina.MemoryNative.SlstrCopyNew((string)managedObj);
1522 }
1523
1524 public void CleanUpNativeData(IntPtr pNativeData)
1525 {
1526 }
1527
1528 public void CleanUpManagedData(object managedObj)
1529 {
1530 }
1531
1532 public int GetNativeDataSize()
1533 {
1534 return -1;
1535 }
1536
1537 internal static ICustomMarshaler GetInstance(string cookie)
1538 {
1539 if (marshaler == null)
1540 {
1541 marshaler = new StringOutMarshaler();
1542 }
1543
1544 return marshaler;
1545 }
1546
1547 static private StringOutMarshaler marshaler;
1548}
1549
1511class StringKeepOwnershipMarshaler: ICustomMarshaler 1550class StringKeepOwnershipMarshaler: ICustomMarshaler
1512{ 1551{
1513 public object MarshalNativeToManaged(IntPtr pNativeData) 1552 public object MarshalNativeToManaged(IntPtr pNativeData)