From 84110040aac8c8999a9c510e418ec8cec1234a81 Mon Sep 17 00:00:00 2001 From: Alexis Christoforides Date: Sun, 5 Oct 2014 22:21:15 -0700 Subject: [PATCH] [runtime] Convert String.InternalSetLength to an icall. Needed for canary support. The change does not have a negative impact on StringBuilder performance; under variable-string-length microbenchmarks it seems to perform ~15-20% faster than the managed implementation. --- mcs/class/corlib/System/String.cs | 20 ++------------------ mono/metadata/boehm-gc.c | 12 ++++++++++++ mono/metadata/gc-internal.h | 2 ++ mono/metadata/icall-def.h | 1 + mono/metadata/sgen-gc.c | 19 +++++++++++++++++++ mono/metadata/string-icalls.c | 7 +++++++ mono/metadata/string-icalls.h | 3 +++ 7 files changed, 46 insertions(+), 18 deletions(-) diff --git a/mcs/class/corlib/System/String.cs b/mcs/class/corlib/System/String.cs index 2a408933eac..65e460647ca 100644 --- a/mcs/class/corlib/System/String.cs +++ b/mcs/class/corlib/System/String.cs @@ -2688,24 +2688,8 @@ namespace System } } - internal unsafe void InternalSetLength (int newLength) - { - if (newLength > length) - throw new ArgumentOutOfRangeException ("newLength", "newLength as to be <= length"); - - // zero terminate, we can pass string objects directly via pinvoke - // we also zero the rest of the string, since the new GC needs to be - // able to handle the changing size (it will skip the 0 bytes). - fixed (char * pStr = &start_char) { - char *p = pStr + newLength; - char *end = pStr + length; - while (p < end) { - p [0] = '\0'; - p++; - } - } - length = newLength; - } + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern void InternalSetLength (int newLength); [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)] // When modifying it, GetCaseInsensitiveHashCode() should be modified as well. diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index a3f8296459a..090f2f7a1dc 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -1291,6 +1291,18 @@ mono_gc_get_los_limit (void) return G_MAXINT; } +void +mono_gc_set_string_length (MonoString *str, gint32 new_length) +{ + mono_unichar2 *new_end = str->chars + new_length; + + /* zero the discarded string. This null-delimits the string and allows + * the space to be reclaimed by SGen. */ + + memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2)); + str->length = new_length; +} + gboolean mono_gc_user_markers_supported (void) { diff --git a/mono/metadata/gc-internal.h b/mono/metadata/gc-internal.h index 8e8c35f8360..7b8836363f8 100644 --- a/mono/metadata/gc-internal.h +++ b/mono/metadata/gc-internal.h @@ -329,6 +329,8 @@ void mono_gc_set_skip_thread (gboolean skip) MONO_INTERNAL; */ gboolean mono_gc_is_disabled (void) MONO_INTERNAL; +void mono_gc_set_string_length (MonoString *str, gint32 new_length) MONO_INTERNAL; + #if defined(__MACH__) void mono_gc_register_mach_exception_thread (pthread_t thread) MONO_INTERNAL; pthread_t mono_gc_get_mach_exception_thread (void) MONO_INTERNAL; diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index 103eb3c4230..257b8332f5f 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -797,6 +797,7 @@ ICALL(STRING_8a, "GetLOSLimit", ves_icall_System_String_GetLOSLimit) ICALL(STRING_9, "InternalAllocateStr", ves_icall_System_String_InternalAllocateStr) ICALL(STRING_10, "InternalIntern", ves_icall_System_String_InternalIntern) ICALL(STRING_11, "InternalIsInterned", ves_icall_System_String_InternalIsInterned) +ICALL(STRING_12, "InternalSetLength", ves_icall_System_String_InternalSetLength) ICALL_TYPE(TENC, "System.Text.Encoding", TENC_1) ICALL(TENC_1, "InternalCodePage", ves_icall_System_Text_Encoding_InternalCodePage) diff --git a/mono/metadata/sgen-gc.c b/mono/metadata/sgen-gc.c index ddbef83fe24..f24fabeac0a 100644 --- a/mono/metadata/sgen-gc.c +++ b/mono/metadata/sgen-gc.c @@ -4360,6 +4360,25 @@ mono_gc_get_los_limit (void) return MAX_SMALL_OBJ_SIZE; } +void +mono_gc_set_string_length (MonoString *str, gint32 new_length) +{ + mono_unichar2 *new_end = str->chars + new_length; + + /* zero the discarded string. This null-delimits the string and allows + * the space to be reclaimed by SGen. */ + + if (nursery_canaries_enabled () && sgen_ptr_in_nursery (str)) { + CHECK_CANARY_FOR_OBJECT (str); + memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2) + CANARY_SIZE); + memcpy (new_end + 1 , CANARY_STRING, CANARY_SIZE); + } else { + memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2)); + } + + str->length = new_length; +} + gboolean mono_gc_user_markers_supported (void) { diff --git a/mono/metadata/string-icalls.c b/mono/metadata/string-icalls.c index 388d866141f..22b1fbbbdb4 100644 --- a/mono/metadata/string-icalls.c +++ b/mono/metadata/string-icalls.c @@ -67,3 +67,10 @@ ves_icall_System_String_GetLOSLimit (void) return (limit - 2 - offsetof (MonoString, chars)) / 2; } + +void +ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length) +{ + mono_gc_set_string_length (str, new_length); +} + diff --git a/mono/metadata/string-icalls.h b/mono/metadata/string-icalls.h index a0b831a1e20..33bcf80378b 100644 --- a/mono/metadata/string-icalls.h +++ b/mono/metadata/string-icalls.h @@ -30,4 +30,7 @@ ves_icall_System_String_InternalIsInterned (MonoString *str) MONO_INTERNAL; int ves_icall_System_String_GetLOSLimit (void) MONO_INTERNAL; +void +ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length) MONO_INTERNAL; + #endif /* _MONO_CLI_STRING_ICALLS_H_ */ -- 2.25.1