[netcore] Implement System.IO.HasOverriddenBeginEndRead(Write)… (mono/mono#17237)
authorEgor Bogatov <egorbo@gmail.com>
Wed, 16 Oct 2019 18:16:51 +0000 (21:16 +0300)
committerMarek Safar <marek.safar@gmail.com>
Wed, 16 Oct 2019 18:16:51 +0000 (20:16 +0200)
* Implement HasOverriddenBeginEndRead and HasOverriddenBeginEndWrite

* fix typo

* clean up

* more clean up

* more clean up

* convert into intrinsics

* handle end* methods

* Update intrinsics.c

* make cache_System_IO_Stream_slots static

* fix race condition

* Rollback to icall

* Update icall.c

* Address feedback

* Address feedback

Commit migrated from https://github.com/mono/mono/commit/886cd73784befd68b45c4fa3fa4f6864fe366139

src/mono/mono/metadata/icall-def-netcore.h
src/mono/mono/metadata/icall.c
src/mono/netcore/System.Private.CoreLib/src/System.IO/Stream.cs

index a292f96..ee593d8 100644 (file)
@@ -109,6 +109,10 @@ HANDLES(GC_7, "_SuppressFinalize", ves_icall_System_GC_SuppressFinalize, void, 1
 HANDLES(GC_9, "get_ephemeron_tombstone", ves_icall_System_GC_get_ephemeron_tombstone, MonoObject, 0, ())
 HANDLES(GC_8, "register_ephemeron_array", ves_icall_System_GC_register_ephemeron_array, void, 1, (MonoObject))
 
+ICALL_TYPE(STREAM, "System.IO.Stream", STREAM_1)
+HANDLES(STREAM_1, "HasOverriddenBeginEndRead", ves_icall_System_IO_Stream_HasOverriddenBeginEndRead, MonoBoolean, 1, (MonoObject))
+HANDLES(STREAM_2, "HasOverriddenBeginEndWrite", ves_icall_System_IO_Stream_HasOverriddenBeginEndWrite, MonoBoolean, 1, (MonoObject))
+
 ICALL_TYPE(MATH, "System.Math", MATH_19)
 NOHANDLES(ICALL(MATH_19, "Abs(double)", ves_icall_System_Math_Abs_double))
 NOHANDLES(ICALL(MATH_20, "Abs(single)", ves_icall_System_Math_Abs_single))
index b5acdb6..bebb92b 100644 (file)
@@ -3505,6 +3505,86 @@ ves_icall_RuntimeMethodInfo_GetGenericMethodDefinition (MonoReflectionMethodHand
        return mono_method_get_object_handle (MONO_HANDLE_DOMAIN (ref_method), result, NULL, error);
 }
 
+#ifdef ENABLE_NETCORE
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (stream, "System.IO", "Stream")
+static int io_stream_begin_read_slot = -1;
+static int io_stream_begin_write_slot = -1;
+static int io_stream_end_read_slot = -1;
+static int io_stream_end_write_slot = -1;
+static gboolean io_stream_slots_set = FALSE;
+
+static void
+init_io_stream_slots (void)
+{
+       MonoClass* klass = mono_class_try_get_stream_class ();
+       mono_class_setup_vtable (klass);
+       MonoMethod **klass_methods = m_class_get_methods (klass);
+       if (!klass_methods) {
+               mono_class_setup_methods (klass);
+               klass_methods = m_class_get_methods (klass);
+       }
+       int method_count = mono_class_get_method_count (klass);
+       int methods_found = 0;
+       for (int i = 0; i < method_count; i++) {
+               // find slots for Begin(End)Read and Begin(End)Write
+               MonoMethod* m = klass->methods [i];
+               if (m->slot == -1)
+                       continue;
+
+               if (!strcmp (m->name, "BeginRead")) {
+                       methods_found++;
+                       io_stream_begin_read_slot = m->slot;
+               } else if (!strcmp (m->name, "BeginWrite")) {
+                       methods_found++;
+                       io_stream_begin_write_slot = m->slot;
+               } else if (!strcmp (m->name, "EndRead")) {
+                       methods_found++;
+                       io_stream_end_read_slot = m->slot;
+               } else if (!strcmp (m->name, "EndWrite")) {
+                       methods_found++;
+                       io_stream_end_write_slot = m->slot;
+               }
+       }
+       g_assert (methods_found <= 4); // some of them can be linked out
+       io_stream_slots_set = TRUE;
+}
+
+MonoBoolean
+ves_icall_System_IO_Stream_HasOverriddenBeginEndRead (MonoObjectHandle stream, MonoError *error)
+{
+       MonoClass* curr_klass = MONO_HANDLE_GET_CLASS (stream);
+       MonoClass* base_klass = mono_class_try_get_stream_class ();
+
+       if (!io_stream_slots_set)
+               init_io_stream_slots ();
+
+       // slots can still be -1 and it means Linker removed the methods from the base class (Stream)
+       // in this case we can safely assume the methods are not overridden
+       // otherwise - check vtable
+       gboolean begin_read_is_overriden = io_stream_begin_read_slot != -1 && curr_klass->vtable [io_stream_begin_read_slot]->klass != base_klass;
+       gboolean end_read_is_overriden = io_stream_end_read_slot != -1 && curr_klass->vtable [io_stream_end_read_slot]->klass != base_klass;
+
+       // return true if BeginRead or EndRead were overriden
+       return begin_read_is_overriden || end_read_is_overriden;
+}
+
+MonoBoolean
+ves_icall_System_IO_Stream_HasOverriddenBeginEndWrite (MonoObjectHandle stream, MonoError *error)
+{
+       MonoClass* curr_klass = MONO_HANDLE_GETVAL (stream, vtable)->klass;
+       MonoClass* base_klass = mono_class_try_get_stream_class ();
+
+       if (!io_stream_slots_set)
+               init_io_stream_slots ();
+
+       gboolean begin_write_is_overriden = curr_klass->vtable [io_stream_begin_write_slot]->klass != base_klass;
+       gboolean end_write_is_overriden = curr_klass->vtable [io_stream_end_write_slot]->klass != base_klass;
+
+       // return true if BeginWrite or EndWrite were overriden
+       return begin_write_is_overriden || end_write_is_overriden;
+}
+#endif
+
 MonoBoolean
 ves_icall_RuntimeMethodInfo_get_IsGenericMethod (MonoReflectionMethodHandle ref_method, MonoError *erro)
 {
index f350cb2..3e0c4e4 100644 (file)
@@ -2,12 +2,16 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Runtime.CompilerServices;
+
 namespace System.IO
 {
        partial class Stream
        {
-               bool HasOverriddenBeginEndRead () => true;
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern bool HasOverriddenBeginEndRead ();
 
-               bool HasOverriddenBeginEndWrite () => true;
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern bool HasOverriddenBeginEndWrite ();
        }
 }