From 5c8cc75a0591dbd0561ac2a642d1e977d62eab98 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 16 Oct 2019 21:16:51 +0300 Subject: [PATCH] =?utf8?q?[netcore]=20Implement=20System.IO.HasOverriddenB?= =?utf8?q?eginEndRead(Write)=E2=80=A6=20(mono/mono#17237)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * 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 | 4 ++ src/mono/mono/metadata/icall.c | 80 ++++++++++++++++++++++ .../System.Private.CoreLib/src/System.IO/Stream.cs | 8 ++- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index a292f96c..ee593d8 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -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)) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index b5acdb6..bebb92b 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -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) { diff --git a/src/mono/netcore/System.Private.CoreLib/src/System.IO/Stream.cs b/src/mono/netcore/System.Private.CoreLib/src/System.IO/Stream.cs index f350cb2..3e0c4e4 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System.IO/Stream.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System.IO/Stream.cs @@ -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 (); } } -- 2.7.4